powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Java [игнор отключен] [закрыт для гостей] / Spring @Cacheable впадает в бесконечный цикл
25 сообщений из 27, страница 1 из 2
Spring @Cacheable впадает в бесконечный цикл
    #39897811
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго вечера!

Не знаю, пользуется ли кто аннотациями спринговыми аннотациями @Cacheable или нет, но есть один очень важный нюанс: не стоит вызывать методы вот так:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
    @Cacheable(value = "myCache", sync = true)
    public String method1(String key) {
        return proxy.method2(key);
    }

    @Cacheable(value = "myCache", sync = true)
    public String method2(String key) {
        return "hello " + key;
    }



т.е. когда один метод с такой аннотацией вызывает другой метод с такой же аннотацией на том же кеше.
Потому что внутри это приведет к вложенному вызову computeIfAbsent на одной и той же ConcurrentHashMap. Если выйдет так, что ключи сгенерируют hash, указывающий на одну и ту же корзину, то все это зависнет в бесконечном цикле в недрах ConcurrentHashMap.

Т.е. например, вот такой код зациклится:
Код: java
1.
map.computeIfAbsent("FB", s -> map.computeIfAbsent("Ea", s1 -> "value"));


все потому что строки "FB" и "Ea" возвращают одинаковый hash и соответственно попадут в одну корзину, и computeIfAbsent сносит башню от этого. Последствия такого кульбита - минус поток выполнения, да не просто залоченого, а в бесконечном цикле, что с моей точки зрения - просто катастрофа.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897846
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rabiter, если тебя послушать то можно подумать что ConcurrentHashMap имеет дефект коллизии хешей
который приводит к зависанию.

Ты это хотел сказать?
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897859
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

Да, это уже обсуждалось здесь:
https://stackoverflow.com/questions/28840047/recursive-concurrenthashmap-computeifabsent-call-never-terminates-bug-or-fea

и здесь на форуме
https://www.sql.ru/forum/1206647/concurrenthashmap-mozhet-poymat-dedlok-pri-odnopotochnom-ispolzovanii

Это не совсем дефект, потому что в документации к ConcurrentHashMap#computeIfAbsent можно найти следующее:
Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map .

Но я не про этот "дефект", а про то, во что он может вылиться, если вот так использовать вложенные вызовы @Cacheable аннотации.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897861
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rabiter, ну ОК.

Но наверное не стоит из кешируемого метода вызывать другой кешируемый.
Убежден что в твоём коде можно зарефакторить общую логику и сделать к ней вызов из двух.

Как бритва Оккама.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897862
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Похоже в девятке пофиксили, ну как, просто бросают исключение теперь, а не уходят в бесконечный цикл. Но мало ли, я вот на 8-ке еще пока.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897865
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
rabiter, ну ОК.

Но наверное не стоит из кешируемого метода вызывать другой кешируемый.
Убежден что в твоём коде можно зарефакторить общую логику и сделать к ней вызов из двух.

Как бритва Оккама.


Да да, все верно, так и придется делать.
Есть еще один вариант, предложенный тут:
https://github.com/ben-manes/caffeine/issues/89
Т.е. в мапу класть не результат выполнения, а CompletableFuture. Развязав таким образом CacheLoader от самого кеша (мапы).
Но что-то рисковать нет желания)
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897882
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Но наверное не стоит из кешируемого метода вызывать другой кешируемый.

в ТОМ же кеше. Смысл этого, мне совершенно не понятен
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897896
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid Kudryavtsev
mayton
Но наверное не стоит из кешируемого метода вызывать другой кешируемый.

в ТОМ же кеше. Смысл этого, мне совершенно не понятен


Ну смысл в том, чтобы создать некий фреймворк, которым могли бы пользоваться программисты "послабее" и не париться.

Вот например пример:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
@Cacheable(value="mimeTypes")
public MimeType getMimeType(String mimeType) {
  List<MimeType> allMimeTypes = proxy.getAllMimeTypes();
  return allMimeTypes.stream().filter(m -> m.getName().equals(mimeType)).get();
}

@Cacheable(value="mimeTypes")
public List<MimeTypes> getAllMimeTypes() {
  return someDBService.getMimeTypes();
}



Тут оба метода кешируются в одном и том же кеше, который инвалидируется сразу как только справочник mime types изменяется.
Ну тут понятно, что кешировать результат первого метода нет смысла - там нет ничего тяжелого, лишь выборка из списка.
Но теперь, если все же кто-нибудь так напишет - нужна дополнительная защита - проверка в runtime, чтобы так Cacheable не использовали. Иначе словить бесконечный цикл, это просто дикость какая-то, не хотелось бы, это же катастрофа.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39897968
lleming
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно уточнить
Если так
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
class ValueGenerator{

    private ValueGenerator proxy;

    @Cacheable(value = "myCache", sync = true)
    public String method1(String key) {
        return proxy.method2(key);
    }

    @Cacheable(value = "myCache", sync = true)
    public String method2(String key) {
        return "hello " + key;
    }
}



то это странно, тк запрос будет мимо кэша посколу ссылка прокси в действительности на реальный класс а не прокси.

Leonid Kudryavtsevв ТОМ же кеше. Смысл этого, мне совершенно не понятен

Тоже так же кажется как то странно даже звучит логически (ИМХО)

Вот еще интересная тема с кэшами
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
    @Cacheable(value = "myCache", sync = true)
    public List<String> method1(String key) {
        //....
    }

    @Cacheable(value = "myCache", sync = true)
    public Set<String> method2(String key) {
       //.....
    }


Потратил много времени пока допер в чем проблема :=)
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898240
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
lleming
Можно уточнить
Если так
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
class ValueGenerator{

    private ValueGenerator proxy;

    @Cacheable(value = "myCache", sync = true)
    public String method1(String key) {
        return proxy.method2(key);
    }

    @Cacheable(value = "myCache", sync = true)
    public String method2(String key) {
        return "hello " + key;
    }
}



то это странно, тк запрос будет мимо кэша посколу ссылка прокси в действительности на реальный класс а не прокси.

Не, я имел ввиду что все вызовы, конечно же, через прокси (я не совсем еще того) :-)
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898245
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
lleming

Leonid Kudryavtsevв ТОМ же кеше. Смысл этого, мне совершенно не понятен

Тоже так же кажется как то странно даже звучит логически (ИМХО)
[/src]

Ну это меня успокаивает, потому что уже как минимум два человека находят такие вызовы бессмысленными. Но опасность-то в том, что если кто-нибудь все-таки так напишет (ну не я, коллеги мои), то есть вероятность словить бесконечный цикл, а это минус поток.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898247
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
    @Cacheable(value = "myCache", sync = true)
    public String method1(String key) {
        return proxy.method2("Mr " + key);
    }

    @Cacheable(value = "myCache", sync = true)
    public String method2(String key) {
        return "hello " + key;
    }




А такой код уже не кажется таким бесмысленным? Т.к. я в кеш не с одним ключем лезу, а с разными (добавил префикс "Mr " + key)?
Так вот если хеши у ключей на одну корзину укажут, то зациклится внутри ConcurrentHashMap
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898248
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А зачем это кешировать?

Код: java
1.
2.
3.
4.
@Cacheable(value = "myCache", sync = true)
    public String method2(String key) {
        return "hello " + key;
    }



Это идеальная быстро вычислимая pure-function в духе функнионального программирования.

Твой пример - неудачен IMHO. Дай нам более приближенный к реальности.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898250
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
lleming

Вот еще интересная тема с кэшами
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
    @Cacheable(value = "myCache", sync = true)
    public List<String> method1(String key) {
        //....
    }

    @Cacheable(value = "myCache", sync = true)
    public Set<String> method2(String key) {
       //.....
    }


Потратил много времени пока допер в чем проблема :=)


Это потому что в спринге поумолчанию метод не участвует в генерации ключа :-) У себя я настроил генерацию ключа таким образом: составной ключ, который состоит из метода + параметры. Тогда получается что для этих двух методов будет разный ключ и соответственно две разные записи в кеше. И мой пример выше тоже получается обретает смысл, потому что эти два метода будут закешированы в одном кеше, но под разными ключами (методы-то разные, хоть и параметр один и тот же).
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898263
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну и не забываем. что сам по себе LRU подходить не для всех задач !
т.ч. у нормально пользователя может возникнуть желание, вместо LRU выбирать какой-то другой алгоритм (очистки кэша)

смутные воспоминания, что mayton какой-то такой топик недавно создавал
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898264
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
А зачем это кешировать?

Код: java
1.
2.
3.
4.
@Cacheable(value = "myCache", sync = true)
    public String method2(String key) {
        return "hello " + key;
    }



Это идеальная быстро вычислимая pure-function в духе функнионального программирования.

Твой пример - неудачен IMHO. Дай нам более приближенный к реальности.

Ну да, эта конструкция не имеет смысла, конечно, потому что кешировать результат конкатинации конечно не имеет смысл...

Давайте вот такой пример:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
    @Cacheable(value = "myCache", sync = true)
    public DocumentTypes getDocumentTypesForUser(String username, String tenant) {
        DocumentTypes allDocTypes = proxy.getAllDocumentTypes(tenant); 
        // ...
        // здесь мы пробегаемся по всем документным типам и составляем
        // новый список в соответствии с правами/локализацией/личных
        // настроек пользователя
        // пусть это in memory операция, но вызывается очень часто,
        // и ее результат выполнения хотелось бы так же в кеше сохранить
       return result;
    }

    @Cacheable(value = "myCache", sync = true)
    public DocumentTypes getAllDocumentTypes(String tenant) {
        return dbService.loadAllDocumentTypes(tenant); // тяжелая операция, поэтому кешируем
    }



Т.е. вот это уже может зациклиться. Workaround простой - использовать разные кеши. Но все же, за этим уже надо следить, а коллеги разные бывают.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898265
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вспомнился афоризм

В компьютерных науках есть две сложности: инвалидация кэша, именование переменных.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898268
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Вспомнился афоризм

В компьютерных науках есть две сложности: инвалидация кэша, именование переменных.


Да да) про это я давно слышал
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898270
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rabiter

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
    @Cacheable(value = "myCache", sync = true)
    public DocumentTypes getDocumentTypesForUser(String username, String tenant) {
        DocumentTypes allDocTypes = proxy.getAllDocumentTypes(tenant); 
        // ...
        // здесь мы пробегаемся по всем документным типам и составляем
        // новый список в соответствии с правами/локализацией/личных
        // настроек пользователя
        // пусть это in memory операция, но вызывается очень часто,
        // и ее результат выполнения хотелось бы так же в кеше сохранить
       return result;
    }

    @Cacheable(value = "myCache", sync = true)
    public DocumentTypes getAllDocumentTypes(String tenant) {
        return dbService.loadAllDocumentTypes(tenant); // тяжелая операция, поэтому кешируем
    }



Т.е. вот это уже может зациклиться. Workaround простой - использовать разные кеши. Но все же, за этим уже надо следить, а коллеги разные бывают.

У тебя здесь по определению должны быть разные кеши. У тебя уникальный ключ для одной функции
username + tenant а для другой - tenant.

Это просто поинт к тому чтобы просто сделать НОРМАЛЬНЫЙ дизайн и проблема ликвидируется.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898273
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid Kudryavtsev
ну и не забываем. что сам по себе LRU подходить не для всех задач !
т.ч. у нормально пользователя может возникнуть желание, вместо LRU выбирать какой-то другой алгоритм (очистки кэша)

смутные воспоминания, что mayton какой-то такой топик недавно создавал


Да, я читал этот топик. Но сейчас меня вопросы очистки не особо пока интересуют (у меня два варианта, как осуществлять очистку есть, чуть позже напишу. Но если кратко, это очистка по событию. И второй вариант - перед чтением кеша - проверка флага, который сбрасывается теми, кто меняют данные, и если флаг сброшен - то и кеш сбрасывается, прямо внутри аспекта). Но, кстати, может и правда использовать разные HashMap для разных методов? Но это будет забавно... Великоват overhead получается. Я думал использовать один ConcurrentHashMap, но к составному ключу просто добавить еще и метод (метод + параметры). И все просто валить в одну большую кучу. На самом деле кеш не будет очень большим в моем случае. Это больше попытка "навести порядок". Сейчас у нас куча полей в бинах типа ConcurrentHashMap или volatile DocumentTypes. Т.е. каждый бин кеширует сам у себя. Плюс такие бины подписаны на события по инвалидации кеша и сбрасывает эти поля просто по событию и все. И таких бинов довольно много. А так можно было бы просто аннотировать методы и все дела.
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898276
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cц#$%ко, мое сообщение пропало (((

Нужно определиться, что же такое для нас КЭШ. Что понимать под этим термином?

На мой взгляд:
1. Это соответствие параметр_ф-ции ==> результат
Что для разных ф-ций БЕСМЫСЛЕННО. Если две ф-ции для одного и того же параметра. возврашают один и тот же результат - значит ф-ции совершенно одинаковые. Т.е. в продакшене это просто или копи-паст или переименование ф-ций.
Обычно реализуется через структуры типа HashMap
2. Политика управления кэшем: размер, алгоритм очистки и прочее
Обычно реализуется через LRU. Но НЕ всегда. Для некоторых применений LRU не лучшей вариант

Таким образом, если мы хотим делать по хорошему:
1. HeshMap для каждой ф-ции должен быть СВОЙ
2. А вот LRU (или аналог) никто не запрешает делать один, на несколько HashMap'ов. Конечно, возможно, нужно кодировать

IMHO & AFAIK

22032391
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898277
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rabiter
Да, я читал этот топик.....

сорри, пред сообщение это был кусок (продолжение) от сообщения выше
почему-то сообщение не опубликовалось (((
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898289
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid Kudryavtsev
ну и не забываем. что сам по себе LRU подходить не для всех задач !
т.ч. у нормально пользователя может возникнуть желание, вместо LRU выбирать какой-то другой алгоритм (очистки кэша)

смутные воспоминания, что mayton какой-то такой топик недавно создавал

Да. Помню такое. Вот тут https://www.sql.ru/forum/1317932/chetvergovaya-invalidaciya-keshey
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898539
Alexey Tomin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rabiter
Это потому что в спринге поумолчанию метод не участвует в генерации ключа :-)


А, так вот оно что

Ну тогда понятно, в чём ошибка.
Да, нужно разные кэши
...
Рейтинг: 0 / 0
Spring @Cacheable впадает в бесконечный цикл
    #39898666
rabiter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, это мне подойдет, использовать по ConcurrentHashMap на метод. Только для методов без параметров это выглядит глуповато, потому что в мапе для них может быть максимум одно значение.
...
Рейтинг: 0 / 0
25 сообщений из 27, страница 1 из 2
Форумы / Java [игнор отключен] [закрыт для гостей] / Spring @Cacheable впадает в бесконечный цикл
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]