Scala - Redis hgetAll 优化 by hscan

56 篇文章 2 订阅
7 篇文章 0 订阅

一.引言

Redis 实际使用过程中,由于 redis hgetAll 数据量过于大,导致线上 redis 进程堵塞,读取缓慢影响任务执行效率,改用 hscan 优化。

二.Case分析

1.hgetAll 为什么慢

hgetAll 获取指定 key 的全部 hash 结果,时间复杂度 O(n) ,hash 的 key 越多,当 kv 值不多时 hgetAll 非常好用,但是使用 hgetAll 获取的数据量越大,获取的性能越低。与之类似的是 hdel,随着 key 的增加,获取的时间并不是完全的线性增加,而是可能出现翻倍的情况。因此对于高并发的场景,要尽量避免在大数据上进行 hgetAll,hdel,emembers 等操作。

2.hscan 怎么代替

scan,hscan 是增量式迭代命令,通过游标进行分段式读取,负载压力从而不会堵塞 redis 线程,但是速度会慢于 hgetall。hscan 主要用到 ScanParams,通过 ScanParams.count() 方法可以设置每次迭代获取的数据量,假设hgetAll redis read峰值很高,正常值 200,那就可以设定 count(200)。还有一个参数是 SCAN_POINTER_START,该字符型变量标记当前获取的游标,当游标为"0"时,代表全部元素获取完毕。

Tips:

hscan 每次返回的结果可能存在重复,最后整合所有结果时需要自己去重

3.还有方法减小压力嘛

A.redis.dump

redis.dump(key) 可以获取对应元素序列化后的内容 Array[Byte],可以使用 redis 相同的序列化协议进行反序列化,从而避免在 redis 客户端执行序列化,缩短时间

B.拆分 key-value

将原始 HashMap 分布在多个 key 上,缩小每个 Hmap 的大小,整体的数据量变化不大

C.加机器

和拆分的思想类似,可以提高 redis 数量,通过 redis-pool 减轻单点 redis 的压力

D.数据量很大

转存 Hbase

三.hscan 实现代码

A.ScanParams 初始化每次迭代的数量,count 为迭代量

B.SCAN_POINTER_START 为计数游标,标记为"0"时代表全部迭代结束

C.scanResult.getResult() 返回 util.Map.Entry 接口,此接口为泛型,定义为Entry<K,V>,转换后存入 map 即可

  def redisHScan(jedis: Jedis, key: String, count: Int = 100): mutable.HashMap[String, String] = {
    val infoMap = mutable.HashMap[String, String]()
    val scanParams = new ScanParams().count(count)
    var cur = redis.clients.jedis.ScanParams.SCAN_POINTER_START
    var cycleIsFinished = false
    while (!cycleIsFinished) {
      val scanResult = jedis.hscan(key, cur, scanParams)
      val result = scanResult.getResult.asScala.map(entry => (entry.getKey, entry.getValue))
      infoMap ++= result
      cur = scanResult.getStringCursor
      if (cur == "0") cycleIsFinished = true
    }
    infoMap
  }
  
  val scanMap = redisHScan(redis, key, 100000)

下面对一个 55w+ key 的 HashMap 进行读取测试:


 ​​​

四.总结

hgetAll 获取大 key 时可以用 hscan 替代,但也需要注意 count 的大小和 Redis 具体的压力,除此之外还有一点需要注意,由于 hscan 是迭代获取执行,所以可能存在数据不一致的情况,获取靠前的数据时,靠后的数据已被修改,这时候会出现先到的数据为老数据,后到的数据为新数据的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIT_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值