问题
spring-data-redis中没有实现关于redis集群的很多命令,最近碰到lettuce在集群中无法执行scan
命令的情况。异常如下:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Scan is not supported across multiple nodes within a cluster.
解决
查看官方文档,发现其实lettuce其实是能支持这种跨节点命令的。官方文档-redis-cluster.cross-slot-command-routing
其中提到了几个类可以执行跨节点命令:
RedisAdvancedClusterCommands
RedisAdvancedClusterAsyncCommands
RedisAdvancedClusterReactiveCommands
根据官方例子
写出大概如下代码即可:
// 获取RedisAdvancedClusterCommands
LettuceClusterConnection con = (LettuceClusterConnection)redisTemplate.getConnectionFactory().getClusterConnection();// 能从LettuceConnetionFactory中直接获取到AbstractRedisClient更好
RedisAdvancedClusterAsyncCommands<byte[], byte[]> nativeConnection = (RedisAdvancedClusterAsyncCommands)con.getNativeConnection();
RedisAdvancedClusterCommands<byte[], byte[]> sync = nativeConnection.getStatefulConnection().sync();
// Cursor及pattern设置
KeyScanCursor<byte[]> scanCursor = null;
ScanArgs scanArgs = new ScanArgs();
scanArgs.match("user:*");
do {
if (scanCursor == null) {
scanCursor = sync.scan(scanArgs);
} else {
scanCursor = sync.scan(scanCursor, scanArgs);
}
keyList.addAll(scanCursor.getKeys());
} while (!scanCursor.isFinished());
// 输出
keyList.forEach(bytes -> {
String s = new String(bytes);
System.out.println(s);
});
ScanArgs配置一下limit属性,性能会更好
源码
Lettuce中集群scan
的实现参照源码:io.lettuce.core.cluster.RedisAdvancedClusterAsyncCommandsImpl#scan(io.lettuce.core.output.KeyStreamingChannel<K>, io.lettuce.core.ScanCursor)
。
大致思路是:逐个节点执行。
后记
可能有更好的方法,以后发现了再补充。
网友评论