使用 Redis Hscan 问题记录

doMore 794 2022-07-03

前言:

在项目中有一个需求,根据中文和英文去搜索用户。

方案

实现

  1. 将用户的基本信息保存在 redis (key=“”,type=hash,value=userInfo)中,
  2. 利用 spring-data-redis 的 redisTemplate hash 类型的 scan 获取 一个 游标(cursor)
  3. 遍历游标,最多获取 10 个用户

问题

这样子实现之后,发现查询速度并没有想的那么快,基本上查询一个用户就需要 1-2 秒,当时整个人都懵了,按理说应该没问题,查询 redis 的速度肯定要比调用其他的服务去查询数据库快,通过打印日志,发现 时间都消耗在 遍历 cursor 获取数据,原来这个算法并不是一下子将整个字典遍历,而是每次遍历固定的数量(即:count),在调用 cur.next() 方法时,进行下一次遍历。本次出现的问题就是在 count 指定的数量太小,花费了大量的时间去建立连接。

解决

  1. 自己封装 lua 脚本,直接从redis拿回一个集合数据
  2. 使用 redisson (org.redisson.spring.data.connection.RedissonConnection)中的 方法 hscan 它 自己封装的一层,拿到的是一个 cursor ,但是 cursor 保存的数据是一个集合,不会与 redis 产生 n 多次的交互。
  3. 根据具体情况指定一个 count 值。

注意

hscan count 参数 失效场景

hash 在一开始的时候并不是 直接使用 dict 结构,而是一个压缩列表的格式,在 压缩列表格式下, count 参数会失效,不论填写数字是多少,都会将匹配规则的数据全量返回。

在 dict 下 count 参数会生效。

在如下两个条件之一满足的时候,Hash集合的编码会由ziplist会转成dict(字典类型编码是哈希表,即hashtable

# 当Hash集合中插入的任意一个Field-Value对中的「Value长度超过64」的时候。
hash-max-ziplist-value 64
# 当Hash集合中的数据项(即Field-Value对)的「数目超过512」的时候
hash-max-ziplist-entries 512