本文目录:

1、big key的定义及问题

2、2023年实际生产事故

3、监控手段

4、预防手段

(一)big key的定义及产生的问题

Redis 的big key是指value占用内存空间较大的键值。通常,针对不同的数据类型会用元素个数或者占用空间大小来衡量bigKey:

String:value占用空间超过5MB(实际使用避免超过1MB);

集合(list,set,zset):成员数量超过1万个(实际使用避免超过2000个);

hash:field成员个数1000个,但value总大小超过100M(实际避免超过10MB);

Big Key对Redis系统性能会带来极其严重的影响,具体问题包括:

1、big key占用较大内存空间,在Redis集群中会造成严重的数据倾斜,存储分布不均匀;

2、当big key同时还是热点key时,还会造成访问倾斜,可能造成单节点访问出现异常;

3、对 big key的操作,尤其是批量操作,较耗时,时间复杂度达到O(N),会造成命令执行阻塞;

4、阻塞网络,bigkey数据较大,会对服务器网卡、所在网络产生一定的影响;

5、影响持久化。AOF重写和bgsave都会同步fork子进程,因为大key,导致写时复制比较耗时。

(二)2023年实际生产事故

1、A系统

现象:交易超时和成功率低预警,以及机房传输设备有端口心跳告警;

影响:用户相应功能不可用,影响用户体验;

原因:存在bigKey,且进行了批量操作(hgetall,hsetall),在交易并发量增大时,批量查询存储操作对Redis性能影响较大,查询缓慢进而导致交易超时。

分析:尽管Redis在Redis4.0引入了后台多线程,Redis6又引入了IO多线程,但Redis的主要命令执行依然是单线程的。如果对单个key进行批量操作,如hashKey的 hgetall,hsetall,执行的时间复杂度是O(N),当并发上来的时候,这种操作是非常低效的,很容易造成客户端阻塞。此外也可能会引发网络阻塞。因为每次获取大 key 产生的网络流量较大,举一个极端的例子,一个 key 的大小是 1 MB,每秒访问量为 1000,那么每秒会产生 1000MB 的流量,这对于普通千兆网卡的服务器来说是难以承受的。

总结:

开发者在使用Redis时要考虑性能的问题,使用Redis也并不是万事大吉,一定要遵循相应的开发规范。笔者建议查看阿里的Redis开发规范,里面也提到了对于big key、批量操作等典型的会阻塞整个主线程的问题。

2、B系统

现象:交易成功率低于最低告警值;

影响:用户查询功能报错,引起客诉;

原因:使用Redis时存在两个big key且还是热点key,且这两个key都在同一个master节点上(RedisCluster集群),导致在高峰期间对应节点访问流量过大,造成了严重的访问倾斜。

分析:并发较高的系统切记不可忽视big key,hot key的问题,热点问题就是其中要考虑的因素,尤其是像秒杀这种超高并发场景。如果把活动库存以 key-value这种简单方式存储到Redis中,抢购中就会出现上述的问题。

对于这种问题,我们可以通过两种方式解决。

1)增加一层本地缓存,减少Redis的访问,基本上多级缓存都这么干;

2)考虑到一致性的问题,用不了本地缓存,像秒杀场景的活动库存这种,就可以将热点key分散存储,一个key拆成多个子key存储。比如某电商进行茅台抢购活动,首先将茅台商品活动库存放到Redis中,茅台就是一个热点key,如maotai,1000,此时就可以将热点key分散存储,茅台抢购是需要预约的,可以将所有预约用户进行分组,Redis会根据组存储活动库存,key可以是 maotai:groupId1 300,maotai:groupId2 300,maotai:groupId3 400,通过这种方式把整个流量分散到不同的节点上,减轻单节点压力。

(三)监控手段

检测key本身会是一件非常耗时的工作,为了避免Redis的检测造成实际业务命令的阻塞,进行bigKey检测时不可在master节点进行,可以在从节点或者使用RDB文件快照进行检测。具体方案总结如下:

1、在从节点执行 –bigkeys命令

Redis天然支持bigkey的检索,通过该命令,Redis会统计每种数据类型的排名第一位的bigKey。这种方式的优点是会进行全量扫描,在对Redis业务数据存储不清楚的情况下使用。但它的缺点也是由于全量扫描带来的性能问题,一种解决方式是在该命令后加上时间间隔,即每隔多长时间扫描一次。 –bigkey -i 3,表示每隔100条指令就会休眠3秒。

2、在从节点执行SCAN命令

实际上bigkey的底层也使用SCAN命令执行,SCAN可以指定某种类型扫描,比如只扫描String,只扫描set类型,相比于直接使用bigkey,SCAN可以缩小扫描范围。

3、离线扫描RDB文件

可以使用redis-rdb-tools等工具离线扫描RDB文件,查看key的内存使用情况,该方案的优势是完全不影响在线Redis节点,完全离线操作。下面的命令是找出字节大于256的key:

rdb –command memory –bytes 256 dump.rdb

4、 慢查询监控

Redis支持对于慢查询的监控,当执行命令超过了设置的阈值之后,会自动将该操作添加到Redis的慢查询日志中,该日志是个链表结构。随后通过SLOWLOG GET命令可以查看到慢查询语句。通过观察慢查询也可查出bigkey的问题。首先要配置慢查询的阈值:

CONFIG SET slowlog-log-slower-than 2

5、Redis时延、带宽等监控

big key的操作会对时延、带宽消耗产生一定的影响,因此对此进行监控可及时发现异常情况。

(四)预防手段

最好的监控就是预防,在写业务代码时,就必须提前考虑big key出现的场景,要提前做好规避方案,主要手段包括:

1、分治,将整个Key进行分片存储,将key打散,减小单key的大小;

2、压缩,可对value值进行序列化、压缩,减小value的存储大小;

3、对 大key操作避免使用批量,避免产生长时间阻塞;

4、对大key进行删除不可用del命令,要使用unlink异步操作;