解决方案 1:
找到了一种解决方案来识别密钥将进入的插槽。 JedisCluster 有一些 API 可以获取它。
int slotNum = JedisClusterCRC16.getSlot(key);
- 提供密钥的槽号。
Set<HostAndPort> redisClusterNode = new HashSet<HostAndPort>();
redisClusterNode.add(new HostAndPort(hostItem, port));
JedisSlotBasedConnectionHandler connHandler = new
JedisSlotBasedConnectionHandler(redisClusterNode, poolConfig, 60);
Jedis jedis = connHandler.getConnectionFromSlot(slotNum);
这为集群中的特定节点提供了 jedis 对象(来自 Jedispool 内部)。
现在有了上面的 jedis 对象,所有命令都可以轻松地为特定节点(在集群中)流水线化
Pipeline pipeline = jedis.pipelined();
pipeline.multi();
for(Entry<String, Map<String, String>> kvf : kvfs.entrySet()) {
pipeline.hmset(kvf.getKey(), kvf.getValue());
}
pipeline.exec();
尽管这种方法(使用 JedisCluster)为密钥提供了适当的节点,但这并没有为我提供预期的性能,我认为这是由于了解插槽号和节点(插槽的)所涉及的过程。
每次我们尝试获取包含插槽号的实际节点(绝地)时,上述过程似乎都会建立与节点(集群中)的物理连接。因此,如果我们有数百万个密钥,这会阻碍性能。
因此,使用 Lettuce 包的另一种方法(如下)帮助我克服了这个问题。
解决方案 2:
使用支持集群模式发送批量命令的Lettuce包。
<groupId>biz.paluch.redis</groupId>
<artifactId>lettuce</artifactId>
<version>4.4.3.Final</version>
代码sn-p:
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()]));
参考:https://github.com/lettuce-io/lettuce-core/wiki/Pipelining-and-command-flushing