问题描述
redis版本5.0.9,redisson的springboot-stater版本是3.24.2,redis中做了一个hash结构的缓存,里面的数据量比较大,有100多万个键值对,之前运行一直正常,最近突然频繁在提取缓存的时候报错:
ERROR [redisson-timer-4-1] 2024-11-19 21:53:38 (PingConnectionHandler.java:89) Unable to send PING command over channel: [id: 0x577dfd31, L:/191.168.0.110:59996 - R:191.168.0.110/191.168.0.110:6379]
org.redisson.client.RedisTimeoutException: Command execution timeout for command: (PING), params: [], Redis client: [addr=redis://191.168.0.110:6379]
当时用来提取hash所有键值对的方法是这样的:
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<String, T> hmget(String key) {
HashOperations<String, String, T> stringObjectObjectHashOperations = redisTemplate.opsForHash();
return stringObjectObjectHashOperations.entries(key);
}
平时用这个方法去提取数据问题不大,也一直没有异常,直到最近缓存量大增,当键值对达到百万级,就出现了redisson的异常信息。
解决方法
解决这个问题的方法是采用Cursor游标提取,代码如下:
/**
* 批量获取hashKey对应的所有键值
*
* @param key
* @return
*/
public Map<String, T> hmgetBatch(String key) {
Map<String, T> result = new HashMap<>();
// 每次返回 SCAN_SIZE 条数据
ScanOptions options = ScanOptions.scanOptions().count(SCAN_SIZE).build();
try (Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(key, options)) {
while (cursor.hasNext()) {
Map.Entry<Object, Object> entry = cursor.next();
result.put((String) entry.getKey(), (T) entry.getValue());
}
}
return result;
}
这样提取在速度上测试下来有10倍提升,同时也不再报错