原实现
public Collection<Session> getActiveSessions() {
Set<Object> keys = redisTemplate.keys(SESSION_PREFIX + "*");
if (keys != null) {
return keys.stream().map(o -> (Session) redisTemplate.opsForValue().get(o)).collect(Collectors.toSet());
} else {
return null;
}
}
问题
redisTemplate.keys() 方法可能会有以下问题:
- 性能问题:
keys()方法会遍历整个 Redis 数据库来匹配指定的模式,如果 Redis 数据库非常大,这可能会导致性能问题,因为它会阻塞 Redis 服务器。 - 潜在的阻塞:在生产环境中使用
keys()方法可能会导致 Redis 服务器阻塞,因为它在执行期间会阻止其他命令的执行。 - 不推荐使用:Redis 官方并不推荐在生产环境中使用
keys()方法,因为它可能会对性能造成影响。 - 不适合大规模数据:当 Redis 数据库中的键非常多时,
keys()方法的执行时间会随着键的数量呈线性增长,因此不适合大规模的数据集。
优化后
public Collection<Session> getActiveSessions() {
String pattern = SESSION_PREFIX + "*";
Set<String> keys =scan(pattern, SCAN_COUNT);
if (CollectionUtils.isNotEmpty(keys)) {
return keys.stream().map(o -> (Session) redisTemplate.opsForValue().get(o)).collect(Collectors.toSet());
}
return null;
}
public Set<String> scan(String pattern, Long count) {
return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> keys = new HashSet<>();
try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(pattern).count(count).build())) {
while (cursor.hasNext()) {
keys.add(new String(cursor.next(), StandardCharsets.UTF_8));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return keys;
});
}