Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

Usando jedis como gravar em um slot/nó específico no cluster redis


Solução 1:
Encontrei uma solução para identificar o slot para o qual as chaves entrariam. JedisCluster tem algumas APIs para obtê-lo.

int slotNum = JedisClusterCRC16.getSlot(key); - Fornece o número do slot da chave.
Set<HostAndPort> redisClusterNode = new HashSet<HostAndPort>();
redisClusterNode.add(new HostAndPort(hostItem, port));

JedisSlotBasedConnectionHandler connHandler = new 
              JedisSlotBasedConnectionHandler(redisClusterNode, poolConfig, 60);

Jedis jedis = connHandler.getConnectionFromSlot(slotNum);

Isso fornece o objeto jedis (do Jedispool internamente) para o nó específico no cluster.
Agora, com o objeto jedis acima, todos os comandos podem ser facilmente canalizados para o nó específico (no cluster)
Pipeline pipeline = jedis.pipelined();
pipeline.multi();
for(Entry<String, Map<String, String>> kvf : kvfs.entrySet()) {
   pipeline.hmset(kvf.getKey(), kvf.getValue());
}
pipeline.exec();

Apesar dessa abordagem (com JedisCluster) ter dado o nó apropriado para o qual as chaves vão para isso não me proporcionou o desempenho esperado, acho que é devido ao procedimento envolvido em saber o número do slot e o nó (do slot).
O procedimento acima parece estabelecer uma conexão física com o nó (no cluster) toda vez que tentamos obter o nó real (jedis) que contém o número do slot. Então, isso atrapalha o desempenho caso tenhamos milhões de chaves.
Então, outra abordagem (abaixo) usando o pacote Lettuce me ajudou a superar isso.

Solução 2:
Usado pacote Lettuce que suporta envio de lote de comandos no modo cluster.
     <groupId>biz.paluch.redis</groupId>
     <artifactId>lettuce</artifactId>
     <version>4.4.3.Final</version>

Fragmento de código:
RedisClusterClient client = RedisClusterClient.create(RedisURI.create("hostname", "port"));
StatefulRedisClusterConnection<String, String> connection = client.connect();

RedisAdvancedClusterAsyncCommands<String, String> commands = connection.async();
// Disabling auto-flushing
commands.setAutoFlushCommands(false);

List<RedisFuture<?>> futures = new ArrayList<>();
// kvf is of type Map<String, Map<String, String>>
for (Entry<> e : kvf.entrySet())
{
   futures.add(commands.hmset( (String) e.getKey(), (Map<String, String>) e.getValue()));
}
// write all commands to the transport layer
commands.flushCommands();
// synchronization example: Wait until all futures complete
LettuceFutures.awaitAll(10, TimeUnit.SECONDS,
futures.toArray(new RedisFuture[futures.size()]));

Ref:https://github.com/lettuce-io/lettuce-core/wiki/Pipelining-and-command-flushing