Lua在Redis中的应用-分页缓存

Lua在Redis中的应用-分页缓存

普通分页

一般分页缓存为直接查出,按页来缓存,这样的缺点是,如果一般有数据增加,所有按页缓存的数据都会失效,对于新增比较多的数据,数据比较大的分页不太适合,所以都是采取,缓存前几页热点访问数据,其它直接读取数据库。

使用SortedSet有序集合来分页

  1. SortedSet: 主要存储有序集合,SortedSet的添加元素指令ZADD key score member [[score,member]…]会给每个添加的元素member绑定一个用于排序的值score,SortedSet就会根据score值的大小对元素进行排序,在这里就可以将createDate当作score用于排序,SortedSet中的指令ZREVRANGE key start stop又可以返回指定区间内的成员,可以用来做分页,SortedSet的指令ZREM key member可以根据key移除指定的成员,所以,SortedSet在这里是最适合的。
  2. 根据取出的member来再去获取具体的内容。

java实现如下:

  private List<Object> getDataByPage(Jedis redis, String key, int pageSize, int pageNum) {
       Set<String> ids = redis.zrange(key, pageNum * pageSize, pageNum * pageSize + pageSize);
        List<Object> result = ids.parallelStream().map(n -> {
            return redis.get(n);
        }).map(n -> {
            return JSON.parseObject(n, Object.class);
        }).collect(Collectors.toList());
        return result;
    }

客户端与Redis使用TCP协议连接,不论是客户端向Redis发送命令还是Redis向客户返回命令的执行结果,都需要网络传输,称为传返时延。大致上来说到本地回环地址(loop back address)的往返时延在数量级上相当于Redis处理一条简单命令(如 lpush list 1 2 3)的时间。如果执行较多的命令,还是有一定的性能影响的。
用Lua脚本如下:

    private List<Object> getDataByPageForLua(Jedis redis, String key, int pageSize, int pageNum) {
        String  script = " local list = redis.call('zrange',KEYS[1],ARGV[1],ARGV[2]) "
                + " local result = {} "
                + " for k,v in pairs(list) do"
                + "  loca r = redis.call('get',KEYS[1] .. '.' .. v) "
                + "  if(r) then table.insert(result,r) eles redis.call('zrem',KEYS[1],v) end"
                + " end return result ";
        List<String> result = (List<String>) redis.eval(script, 1,key,pageSize*pageNum+"",(pageSize*pageNum+pageSize)+"");
        if(result!=null) return result.stream().map(n->{
            return JSON.parseObject(n, Object.class);
        }).collect(Collectors.toList());
        else return null;
    }

但如此写在集群情况下有一个问题,就是脚本会根据访问的KEYS命中集群中的一个node ,脚本里面对redis的操作都应在同一个node上,不然会报请求的KEY不在该NODE上,如果要避免这种情况,就要使用设置HashTag。使脚本与操作的KEY在同一个NODE上 可看https://redis.io/topics/cluster-spec
设置好:脚本的KEY为{key} 该key作为有序集合的key,然后用{key}.v 来做为获取具体信息的key.

注意

这种HashTag使KEY强制写在一个NODE上的方式是不提倡的,要从数据保存开始就要规则好KEY的规则和分部。不然会使键Key在集群中分布不均,运维同志们对集群的扩容会带来麻烦。下面在Redis中Lua脚本相关命令及注意事项提供了一个折中的办法。还望关注。切切。。。。。

参考
redis.io

猜你喜欢

转载自blog.csdn.net/lhn1234321/article/details/79019120