背景:redis集群
执行lua脚本时
不同于单机情况,lua脚本在执行时需要确保key在同一个node节点上,换句话说也就是需要保证 slot=crc16%16384,通过对key进行hash运算,其slot会分布在同一个node节点所属范围。
解决思路:
为了使key都落在一个node节点上可以通过添加 {} hashTag来实现。
原理:
相同的hashtag被分配到相同的节点,相同的槽。
hash算法采用crc16。crc16算法为redis自己封装的,源码位置:https://github.com/redis/redis/blob/6.2.6/src/crc16.c。
golang选择客户端
一开始复用了项目里存在的golang客户端 即采用的 go-redis
github.com/go-redis/redis v6.15.9+incompatible
项目上线后通过granfa监控打点观测到redis的集群远超预想
从上面图形可以看出redis集群的p98响应在k级毫秒以上,其中间断是因为依次排除怀疑的点[qps为300,属实比较低了😱 ]
- lua脚本太复杂导致redis执行较慢(😓 吃了知识点掌握不牢固的亏,仅用 exists 进行测试发现无变化 )
- 怀疑集群存在某节点故障(👺 换成单节点验证发现 无变化)
- 怀疑命中key的概率低的问题(:pleading_face: 换成redis中存在的key验证 无变化)
- 将问题还是放在了redis集群上 ,还好此集群未正式使用(也是敢压测的原因[👀 要对线上环境抱有敬畏之心👀])
执行下述命令进行redis的压测:
redis-benchmark -h 127.0.0.1 -p 6379 -t set,get -n 10000 -q
redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 60
从压测数据来看 latency 平均为15.5906ms,观测还可行。而其set命令平均不到3k,对集群还是有所
怀疑【有可能网络带宽非本地原因,此处无确定结论】,对比了另外一组redis集群发现无影响
- 集群没问题,命令也简单(大佬的帮助下开始测试golang客户端的问题)
原使用的客户端
1、mod文件
github.com/go-redis/redis v6.15.9+incompatible
2、部分代码【注意6.15.9的时候SMembers 无上下文概念】
//构建客户端
ClusterPool := redis2.NewClusterClient(&redis2.ClusterOptions{
Addrs: strings.Split(addr,","),
})
//执行命令并统计耗时
fmt.Println("时间redis cluster client begin:", time.Now())
testData := ClusterPool.SMembers("798176a1b809edaf956bb2c6ceda9280")
fmt.Println("时间redis cluster client end:", time.Now())
fmt.Println(testData) //为了验证成功输出数据
原使用的客户端升级下
1、mod文件
github.com/go-redis/redis/v8 v8.11.5
2、部分代码【此时SMembers 存在上下文了】
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
//构建客户端
ClusterPool := redis2.NewClusterClient(&redis2.ClusterOptions{
Addrs: strings.Split(addr,","),
})
//执行命令并统计耗时
fmt.Println("时间redis cluster client begin:", time.Now())
testData := ClusterPool.SMembers(ctx,"798176a1b809edaf956bb2c6ceda9280")
fmt.Println("时间redis cluster client end:", time.Now())
fmt.Println(testData) //为了验证成功输出数据
Nice的客户端
1、mod文件
2、部分代码
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
//构建客户端
cluster, _ := (radix.ClusterConfig{}).New(ctx, strings.Split(addr,","))
//执行命令并统计耗时
fmt.Println("时间redis cluster client begin:", time.Now())
str:=[]string{}//此处一定要预先知道存储的类型
err:= cluster.Do(ctx, radix.Cmd(&str, "smembers", "798176a1b809edaf956bb2c6ceda9280"))
fmt.Println("时间redis cluster client end:", time.Now())
fmt.Println(testData,err) //为了验证成功输出数据
上述两图分别为 radix 与 go—redis(v6),radix 与 go-redis(v8),实验证明 v8是远强于v6的,但是与radix还是有10倍之差
友情提示,选用客户端的时候可以依照官方推荐的包
经过上述疑问点的排除法,最后采用radix的客户端,其耗时如下:
从上图可以看到redis集群在10k请求的情况下,p98为1.4ms左右,符合预期。大工高成~