Spring-Data-Redis с Jedis putIfAbsent для распределенной блокировки - некорректное поведение - PullRequest
0 голосов
/ 29 октября 2019

У меня есть некоторые проблемы при использовании Spring Data Redis для создания распределенной блокировки. Для этого используется метод putIfAbsent из CacheManager.

С точки зрения высокого уровня операция выглядит примерно так:

if (manager.putIfAbsent(parameters) == null) {
   executeOperation();
}

Из реализации putIfAbsent кажется, что операция setNXиз базового драйвера Jedis.

Код реализации Spring выглядит примерно так:

if (!connection.setNX(keyBytes, value)) {
   return connection.get(keyBytes);
}
maintainKnownKeys(element, connection);
processKeyExpiration(element, connection);

setNX соединения - это просто делегирование действительной клиентской операции. В реализации этого метода есть что-то вроде:

JedisConverters.toBoolean(jedis.setnx(key, value));

Поэтому я столкнулся с двумя отдельными проблемами:

  1. Мой executeOperation () былодновременно выполняется двумя отдельными процессами. (Лишь несколько случаев этой проблемы).

  2. Я столкнулся с ситуацией, когда ключ оставался и срок его действия не истек. Это означает, что код processKeyExpiration (element, connection) не был выполнен. Это означает, что setNx, выполненный как ключ, не был добавлен и возвращен до этого оператора, но фактически ключ был добавлен.

В большинстве случаев все работает нормально. Ключевой сериализатор: StringRedisSerializer.

Я использую: spring-data-redis 1.8.23.RELEASE jedis 2.9.3

Могут ли быть некоторые проблемы с окружающей средой, которые неправильно обрабатываютсяДжедай, или как то так? Кто-нибудь достиг такого? Можно ли попробовать какое-нибудь исправление, обновление библиотеки?

1 Ответ

1 голос
/ 30 октября 2019

Так что я сделал немного больше анализа по этому вопросу. И кажется, что из-за того, как реализован putIfAbsent, он подвержен гонкам, если используется в нескольких процессах / потоках.

Этот факт объясняется тем, что ряд команд для реализации putIfAbsent, setNX, expire, get, не является транзакционным и из-за надлежащих условий (длительные операции, не правильная логика выселения) склонен к некорректному поведению.

Аналогичное объяснение того, как выполнять распределенную блокировку на основе операции Redis setNX, можно найти здесь Команда Redis setNX .

Реализация из putIfAbsent склонна к некорректному поведению при использовании для блокировки аналогично тому, как описано в приведенной выше документации.

Итак, подведем итог, возможно, это не лучшийИдея использовать putIfAbsent с драйвером Jedis для распределенной блокировки, по крайней мере, в этой версии Spring, поскольку, начиная с 2.xx, я знаю, что реализация немного изменилась.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...