9

:看我如何把Redis使用优化到极致

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzU5ODUwNzY1Nw%3D%3D&%3Bmid=2247485168&%3Bidx=1&%3Bsn=c1721479338511c0472e9e2c8d4ff576
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

我们有个这样的需求:每天每一个抢购商品只能买一次,并且全场抢购商品总购买次数不允许超过5次。那么,整个商品限购的流程大概如下图所示: mINFve6.jpg!web

那么,在每次购买成功商品成功后,发送的MQ大概是这样的(假设当前这笔订单有两件抢购商品):

这条消息表示860000000000001这个用户在1581001673012这个时间点(北京时间为2020/02/06 23:07:53)在A045这个商户分别购买了商品ID为599055114591和599055114592两样商品。

那么,当消费这条信息后,更新频控的几条关键Redis命令如下(上面的需求不是重点, 优化下面5条命令才是本文的重点 ):

我们首先了解一下执行一条Redis命令耗时由哪几部分组成:发送命令网络传输时间,命令在Redis服务端队列中等待的时间,命令执行的时间(Redis中的slowlog只是检测这一步骤的时间),结果返回的Redis客户端的时间。如下图所示: UBRRbia.jpg!web

上面的业务总计涉及5条Redis命令,每条命令都需要经过这些步骤,可想而知性能真的弱爆了(可能整个执行过程还不需要10ms,但还是弱爆了)。

  • 第1次优化

第一次优化非常简单,稍微有点经验就能看出来,利用hmset命令将两条hmset命令合二为一,优化后的Redis命令如下:

  • 第2次优化

第二次优化将set和expire命令合二为一,这个一般对Redis有点了解的也知道如何优化:

  • 第3次优化

第3次优化需要借助pipeline,简直就是Redis优化的一大杀器。不过,需要注意的是在 RedisCluster中使用pipeline时必须满足pipeline打包的所有命令key在RedisCluster的同一个slot上 。如果打包命令的key不在同一个slot上,就会报错。所以我们需要分两批打包:

经过第3次的优化后,这些命令还是需要2次网络交互。较劲的我还是不甘心,想要将其优化到只需要一次网络交互即可,有没有办法?当然有!

  • 第4次优化

这次优化利用了一个高级特性: hashtag 。是啥子意思呢?我们知道,RedisCluster总计有16*1024=16384个slot。那么执行一条Redis命令时,其key对应的是哪个slot呢?是利用这样一个计算公式得到的: slot = CRC16(key)%16384 ,示意图如下: IJ3IB3y.jpg!web

也就是说,默认情况下,key在哪个slot上,与key有关。那么,我们能否只 让key在哪个slot上与部分key有关 呢?当然可以,这就是hashtag特性。用法非常简单,假设一个key是mall:sale:freq:ctrl:860000000000001,我们只需要用{}将key中我们需要的那部分包括起来即可。例如,我们只想让其根据用户IMEI计算即可,那么key是这样的:mall:sale:freq:ctrl:{860000000000001}。只要key中有{860000000000001}这一部分,就一定落在同一个slot上。

所以,第四次优化以后的命令执行如下所示:

mARVbur.jpg!web 优化后,5条Redis命令压缩到3条Redis命令,并且3条Redis命令只需要发送一次,并且结果也一次就能全部返回。简直 完美!

  • 注意事项

我们在使用hashtag特性时,一定要注意, 不能把key的离散性变得非常差 。以本文为例,没有利用hashtag特性之前,key是这样的:mall:sale:freq:ctrl:860000000000001,很明显这种key由于与用户相关,所以离散性非常好。而使用hashtag以后,key是这样的:mall:sale:freq:ctrl:{860000000000001},这种key还是与用户相关,所以离散性依然非常好。我们千万不要这样来使用hashtag特性,例如将key设置为:mall:{sale:freq:ctrl}:860000000000001。这样的话,无论有多少个用户多少个key,其{}中的内容完全一样都是sale:freq:ctrl,也就是说,所有的key都会落在同一个slot上,导致整个Redis集群出现严重的倾斜问题。

END

如果读完觉得有收获的话,欢迎点【好看】,关注【阿飞的博客】,查阅更多精彩历史!!!

UZ7B7n7.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK