Redis循环慢接口优化

原慢接口

List<String> keys = new ArrayList<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"));

List<String> res = new ArrayList<>();
for (String key : keys) {
    String value = (String) redisTemplate.opsForValue().get(key);
    if (value == null) {
        value = dataMapper.getValueFromDB(key);
        redisTemplate.opsForValue().set(key, value, 60 * 60, TimeUnit.SECONDS);
        res.add(value);
    }
}
return res;

原因分析

  1. 当keys 数据过大,RTT时间会变大。

    多个Redis命令之间会有往返时间消耗。

    使用MGET、Pipelined可以减少RTT时间

  2. 首次进入此代码域,由于缓存为空,全部走数据库,也会导致接口变慢。

解决方式

Pipelined、MGET 能批量获取数据,但注意元素个数

Pipelined

注意:Redis集群部署时,不同的key可能对应不同实例节点,不能被处理。

List<String> keys = new ArrayList<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"));

List<String> res = new ArrayList<>();
List list = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
    for (String key : keys) {
        connection.get(key.getBytes());
    }
    return null;
});
// 缓存不存在的keys
List<String> nullKeys = new ArrayList<>();
for (int i = 0; i < keys.size(); i++) {
    if (list.get(i) == null) {
        nullKeys.add(keys.get(i));
    } else {
        res.add((String) list.get(i));
    }
}
// 缓存中不存在的值调用 数据库批量查询
Map<String, String> values = dataMapper.getBatchValue(nullKeys);
// 添加返回值,并更新缓存
values.forEach((key, value) -> {
    redisTemplate.opsForValue().set(key, value, 60 * 60, TimeUnit.SECONDS);
    res.add(value);
});
return res;

MGET

List<String> keys = new ArrayList<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"));

List<String> res = new ArrayList<>();
List list = redisTemplate.opsForValue().multiGet(keys);
// 缓存不存在的keys
List<String> nullKeys = new ArrayList<>();
for (int i = 0; i < keys.size(); i++) {
    if (list.get(i) == null) {
        nullKeys.add(keys.get(i));
    } else {
        res.add((String) list.get(i));
    }
}
// 缓存中不存在的值调用 数据库批量查询
Map<String, String> values = dataMapper.getBatchValue(nullKeys);
// 添加返回值,并更新缓存
values.forEach((key, value) -> {
    redisTemplate.opsForValue().set(key, value, 60 * 60, TimeUnit.SECONDS);
    res.add(value);
});
return res;
posted @ 2023-07-26 00:02  帅气的涛啊  阅读(68)  评论(0编辑  收藏  举报