首页 » Web前端 » phpredis没有hscan技巧_运用Redis的HSCAN敕令碰着的一个问题

phpredis没有hscan技巧_运用Redis的HSCAN敕令碰着的一个问题

访客 2024-12-08 0

扫一扫用手机浏览

文章目录 [+]

关注公众年夜众号【Java耕耘者】,专注于Spring源码剖析、Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式等全栈技能,定期视频教程分享,关注后回答 Java ,领取我为你精心准备的 Java 干货

最近在做一个项目时候利用Redis存放客户端展示的订单列表,列表须要进行分页。
由于笔者先前对Redis的各种数据类型的利用场景并不是十分熟习,于是先入为主地看到Hash类型:

phpredis没有hscan技巧_运用Redis的HSCAN敕令碰着的一个问题

USER_ID:1 ORDER_ID:ORDER_XX: {\"大众amount\公众: \公众100\"大众,\"大众orderId\"大众:\公众ORDER_XX\"大众} ORDER_ID:ORDER_YY: {\"大众amount\"大众: \"大众200\"大众,\"大众orderId\"大众:\"大众ORDER_YY\公众}

觉得Hash类型完备知足需求实现的场景。
然后想当然地考虑利用HSCAN命令进行分页,引发了后面碰着的问题。

phpredis没有hscan技巧_运用Redis的HSCAN敕令碰着的一个问题
(图片来自网络侵删)

SCAN和HSCAN命令

SCAN命令如下:

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]// 返回值如下:// 1. cursor,数值类型,下一轮的起始游标值,0代表遍历结束// 2. 遍历的结果凑集,列表

SCAN命令在Redis2.8.0版本中新增,韶光繁芜度打算如下:每一轮遍历的韶光繁芜度为O(1),所有元素遍历完毕直到游标cursor返回0的韶光繁芜度为O(N),个中N为凑集内元素的数量。
SCAN是针对全体Database内的所有KEY进行渐进式的遍历,它不会壅塞Redis,也便是利用SCAN命令遍历KEY的性能会优于KEY 命令。
对付Hash类型有一个衍生的命令HSCAN专门用于遍历Hash类型及其干系属性(Field)的字段:

HSCAN key cursor [MATCH pattern] [COUNT count]// 返回值如下:// 1. cursor,数值类型,下一轮的起始游标值,0代表遍历结束// 2. 遍历的结果凑集,是一个映射

笔者当时没有详细查阅Redis的官方文档,想当然地认为Hash类型的分页大略如下(假设每页数据只有1条):

// 第一页HSCAN USER_ID:1 0 COUNT 1 <= 这里认为返回的游标值为1// 第二页HSCAN USER_ID:1 1 COUNT 1 <= 这里认为返回的游标值为0,结束迭代

实际上,实行的结果如下:

HSCAN USER_ID:1 0 COUNT 1// 结果0 ORDER_ID:ORDER_XX {\公众amount\公众: \"大众100\公众,\公众orderId\"大众:\"大众ORDER_XX\"大众} ORDER_ID:ORDER_YY {\公众amount\"大众: \公众200\公众,\"大众orderId\"大众:\"大众ORDER_YY\"大众}

也便是在第一轮遍历的时候,KEY对应的所有Field-Value已经全量返回。
笔者考试测验增加哈希凑集KEY = USER_ID:1里面的元素,但是数据量相对较大的时候,依然没有达到预期的分页效果;另一个方面,考试测验修正命令中的COUNT值,创造无论如何修正COUNT值都不会对遍历的结果产生任何影响(也便是还是在第一轮迭代返回全部结果)。
百思不得其解的情形下,只能仔细翻阅官方文档探求办理方案。
在SCAN命令的COUNT属性描述中找到了缘故原由:

大略翻译理解一下:

SCAN命令以及其衍生命令并不担保每一轮迭代返回的元素数量,但是可以利用COUNT属性凭履历调度SCAN命令的行为。
COUNT指定每次调用该当完成遍历的元素的数量,以便于遍历凑集,实质只是一个提示值。

COUNT默认值为10。
当遍历的目标Set、Hash、Sorted Set或者Key空间足够大可以利用一个哈希表表示并且不该用MATCH属性的条件下,Redis做事端会返回COUNT或者比COUNT大的遍历元素结果凑集。
当遍历只包含Integer值的Set凑集(也称为intsets),或者ziplists类型编码的Hash或者Sorted Set凑集(解释这些凑集里面的元素占用的空间足够小),那么SCAN命令会返回凑集中的所有元素,直接忽略COUNT属性。

把稳第3点,这个便是在Hash凑集中利用HSCAN命令COUNT属性失落效的根本缘故原由。
Redis配置中有两个和Hash类型ziplist编码的干系配置值:

hash-max-ziplist-entries 512hash-max-ziplist-value 64

在如下两个条件之一知足的时候,Hash凑集的编码会由ziplist会转成dict:

当Hash凑集中的数据项(即Field-Value对)的数目超过512的时候。
当Hash凑集中插入的任意一个Field-Value对中的Value长度超过64。

当Hash凑集的编码会由ziplist会转成dict,Redis为Hash类型的内存空间占用优化相称于失落败了,降级为相对花费更多内存的字典类型编码,这个时候,HSCAN命令COUNT属性才会起效。

案例验证

大略验证一下上一节得出的结论,写入一个测试数据如下:

// 70个XHSET USER_ID:2 ORDER_ID:ORDER_XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // 70个YHSET USER_ID:2 ORDER_ID:ORDER_YYY YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

接着开始测试一下HSCAN命令:

// 查看编码object encoding USER_ID:2// 编码结果hashtable// 第一轮迭代HSCAN USER_ID:2 0 COUNT 1// 第一轮迭代返回结果2 ORDER_ID:ORDER_YYY YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY// 第二轮迭代 HSCAN USER_ID:2 2 COUNT 10 ORDER_ID:ORDER_XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

测试案例中故意让两个值的长度为70,大于64,也便是让Hash凑集转变为dict(hashtable)类型,使得COUNT属性生效。
但是,这种做法是放弃了Redis为Hash凑集的内存优化。
显然,HSCAN命令天然不是为了做数据分页而设计的,而是为了渐进式的迭代(也便是如果须要迭代的凑集很大,也不会壅塞Redis做事)。
以是笔者末了放弃了利用HSCAN命令,探求更适宜做数据分页查询的其他Redis命令。

小结

通过这大略的踩坑案例,笔者得到一些履历:

切忌先入为主,利用中间件的时候要结合实际的场景。
利用工具的之前要仔细阅读工具的利用手册。
要通过一些案例验证自己的猜想或者推导的结果。

Redis供应的API十分丰富,后面该当还会碰着更多的踩坑履历。

为了感谢支持我的朋友!
整理了一份Java高等架构资料、Spring源码剖析、Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式等资料。
私信回答:555领取

标签:

相关文章

phparraymapkey技巧_HashMap面试题

1.两个工具的Hashcode值相等,但是两个工具的内容值不一定相等;---Hash冲突的问题2.两个工具的值Equals比较相等...

Web前端 2024-12-09 阅读0 评论0