(салат) READONLY Вы не можете писать против подчиненного только для чтения

Мне нужна помощь. Наша служба использует версию салата 5.1.6, и в общей сложности развернуто 22 узла докеров.
Всякий раз, когда служба развертывается, появляется несколько узлов докеров ОШИБКА: ТОЛЬКО ДЛЯ ЧТЕНИЯ Вы не можете писать против Ведомое устройство только для чтения.
Перезапустите проблемный докер-узел. ОШИБКА больше не появляется.

  • Конфигурация сервера Redis:

8 master 8 slave
stop-write-on-bgsave-error no
slave-serve-stale-data yes
slave-only read yes
с поддержкой кластера yes
файл конфигурации кластера /data/server/redis-cluster/{port}/conf/node.conf

  • конфигурация салата:
ClientResources res = DefaultClientResources.builder()
        .commandLatencyPublisherOptions(
                DefaultEventPublisherOptions.builder()
                        .eventEmitInterval(Duration.ofSeconds(5))
                        .build()
        )
        .build();
redisClusterClient = RedisClusterClient.create(res, REDIS_CLUSTER_URI);
redisClusterClient.setOptions(
        ClusterClientOptions.builder()
                .maxRedirects(99)
                .socketOptions(SocketOptions.builder().keepAlive(true).build())
                .topologyRefreshOptions(
                        ClusterTopologyRefreshOptions.builder()
                                .enableAllAdaptiveRefreshTriggers()
                                .build())
                .build());
RedisAdvancedClusterCommands<String, String> command = redisClusterClient.connect().sync();
command.setex("some key", 18000, "some value");
  • Исключение, которое появляется:
io.lettuce.core.RedisCommandExecutionException: READONLY You can't write against a read only slave.
    at io.lettuce.core.ExceptionFactory.createExecutionException(ExceptionFactory.java:135)
    at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:122)
    at io.lettuce.core.cluster.ClusterFutureSyncInvocationHandler.handleInvocation(ClusterFutureSyncInvocationHandler.java:123)
    at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80)
    at com.sun.proxy.$Proxy135.setex(Unknown Source)
    at com.xueqiu.infra.redis4.RedisClusterImpl.lambda$setex$164(RedisClusterImpl.java:1489)
    at com.xueqiu.infra.redis4.RedisClusterImpl$$Lambda$1422/1017847781.apply(Unknown Source)
    at com.xueqiu.infra.redis4.RedisClusterImpl.execute(RedisClusterImpl.java:526)
    at com.xueqiu.infra.redis4.RedisClusterImpl.executeTotal(RedisClusterImpl.java:491)
    at com.xueqiu.infra.redis4.RedisClusterImpl.setex(RedisClusterImpl.java:1489)

person singgel    schedule 20.07.2020    source источник
comment
кластер redis версии 4.0.10, сервер redis не выполняет аварийное переключение в течение этого периода.   -  person singgel    schedule 28.07.2020
comment
Подчиненные устройства, соответствующие запросам на запись, отправленным этими ошибочными узлами докеров, не совпадают.   -  person singgel    schedule 28.07.2020
comment
Интересно, что эта проблема связана с (неправильной) конфигурацией Redis Cluster. Мне не удалось воспроизвести ответы READONLY, так как Redis Cluster обычно отправляет перенаправление MOVED для команд записи в реплике.   -  person mp911de    schedule 03.08.2020
comment
@ mp911de Да, как вы сказали, это вызвано проблемами кластера, например: github.com/ redis/redis/issues/2969, но может ли салат выполнять проверку при получении информации о топологии на стороне клиента? , Например: redis-cli --cluster check 127.0.0.1:6379   -  person singgel    schedule 10.08.2020


Ответы (1)


  1. Перед лицом распределенного промежуточного программного обеспечения клиентская сторона поместит некоторые разделы, сегментирование и другие отношения на клиентскую сторону для управления.

И салат — это управление сопоставлением слотов кластера Redis:

Принятый метод заключается в использовании массива slotCache и локальном кэшировании узла, соответствующего каждому слоту, в виде массива.

При наличии ключа, который необходимо прочитать и записать на сервер, слот будет вычисляться через CRC16 в клиенте, а затем узел будет получен в кеше.

  1. Когда сервер кластера redis выполняет управление кластером, он записывает отношение сопоставления между слотом и узлом в локальном файле node.conf каждого узла.

Когда данные пинг-понга обмениваются через протокол сплетен, эта информация метаданных транслируется для формирования окончательной согласованной информации метаданных.

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

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

person singgel    schedule 03.08.2020
comment
Поэтому в настоящее время вы должны проверить, есть ли в вашем кластере Redis проблемы с сопоставлением слотов. Например: github.com/redis/redis/issues/2969 - person singgel; 03.08.2020