• Redis中Bigkey的产生原因及危害
  • 发布于 1个月前
  • 43 热度
    0 评论
一、背景
Redis运维过程中,由于Bigkey的存在,会影响业务程序的响应速度,严重的还会造成可用性损失,DBA也一直和业务开发方强调 Bigkey 的规避方法以及危害,但是Bigkey一直没有完全避免。全网Redis集群有2200个以上,实例数量达到4.5万以上,在当前阶段进行一次全网 Bigkey检查,估计需要以年为时间单位,非常耗时。我们需要新的思路去解决Bigkey问题。

二、Bigkey 介绍
2.1、什么是 Bigkey
在Redis中,一个字符串类型最大可以到512MB,一个二级数据结构(比如hash、list、set、zset等)可以存储大约40亿个(2^32-1)个元素,但实际上不会达到这么大的值,一般情况下如果达到下面的情况,就可以认为它是Bigkey了。
【字符串类型】: 单个string类型的value值超过1MB,就可以认为是Bigkey。
【非字符串类型】:哈希、列表、集合、有序集合等, 它们的元素个数超过2000个,就可以认为是Bigkey。

2.2 Bigkey是怎么产生的
我们遇到的Bigkey一般都是由于程序设计不当或者对于数据规模预料不清楚造成的,比如以下的情况。
【统计】:遇到一个统计类的key,是记录某网站的访问用户的IP,随着时间的推移,网站访问的用户越来越多,这个key的元素数量也会越来越大,形成Bigkey。
【缓存】: 缓存类key一般是这样的逻辑,将数据从数据库查询出来序列化放到Redis里,如果业务程序从Redis没有访问到,就会查询数据库并将查询到的数据追加到Redis缓存中,短时间内会缓存大量的数据到Redis的key中,形成Bigkey。
【队列】:把Redis当做队列使用,处理任务,如果消费出现不及时情况,将导致队列越来越大,形成Bigkey。
这三种情况,都是我们实际运维中遇到的,需要谨慎使用,合理优化。

2.3 Bigkey 的危害
我们在运维中,遇到Bigkey的情况下,会导致一些问题,会触发监控报警,严重的还会影响Redis实例可用性,进而影响业务可用性,在需要水平扩容时候,可能导致水平扩容失败。

2.3.1内存空间不均匀
内存空间不均匀会不利于集群对内存的统一管理,有数据丢失风险。下图中的三个节点是同属于一个集群,它们的key的数量比较接近,但内存容量相差比较多,存在Bigkey的实例占用的内存多了4G以上了。

可以使用使用Daas平台“工具集-操作项管理”,选择对应的slave实例执行分析,找出具体的Bigkey。

2.3.2 超时阻塞
Redis是单线程工作的,通俗点讲就是同一时间只能处理一个Redis的访问命令,操作Bigkey的命令通常比较耗时,这段时间Redis不能处理其他命令,其他命令只能阻塞等待,这样会造成客户端阻塞,导致客户端访问超时,更严重的会造成master-slave的故障切换。造成阻塞的操作不仅仅是业务程序的访问,还有key的自动过期的删除、del删除命令,对于Bigkey,这些操作也需要谨慎使用。
超时阻塞案例
我们遇到一个这样超时阻塞的案例,业务方反映程序访问Redis集群出现超时现象,hkeys访问Redis的平均响应时间在200毫秒左右,最大响应时间达到了500毫秒以上,如下图。

hkeys是获取所有哈希表中的字段的命令,分析应该是集群中某些实例存在hash类型的Bigkey,导致hkeys命令执行时间过长,发生了阻塞现象。
1.使用Daas平台“服务监控-数据库实例监控”,选择master节点,选择Redis响应时间监控指标“redis.instance.latency.max”,如下图所示,从监控图中我们可以看到:
(1)正常情况下,该实例的响应时间在0.1毫秒左右。
(2)监控指标上面有很多突刺,该实例的响应时间到了70毫秒左右,最大到了100毫秒左右,这种情况就是该实例会有100毫秒都在处理Bigkey的访问命令,不能处理其他命令。

通过查看监控指标,验证了我们分析是正确的,是这些监控指标的突刺造成了hkeys命令的响应时间比较大,我们找到了具体的master实例,然后使用master实例的slave去分析下Bigkey情况。

2.使用Daas平台“工具集-操作项管理”,选择slave实例执行分析,分析结果如下图,有一个hash类型key有12102218个fields。

3. 和业务沟通,这个Bigkey是连续存放了30天的业务数据了,建议根据二次hash方式拆分成多个key,也可把30天的数据根据分钟级别拆分成多个key,把每个key的元素数量控制在5000以内,目前业务正在排期优化中。优化后,监控指标的响应时间的突刺就会消失了。

2.3.3 网络阻塞
Bigkey的value比较大,也意味着每次获取要产生的网络流量较大,假设一个Bigkey为10MB,客户端每秒访问量为100,那么每秒产生1000MB的流量,对于普通的千兆网卡(按照字节算是128MB/s)的服务器来说简直是灭顶之灾。而且我们现在的Redis服务器是采用单机多实例的方式来部署Redis实例的,也就是说一个Bigkey可能会对同一个服务器上的其他Redis集群实例造成影响,影响到其他的业务。

2.3.4 迁移困难

我们在运维中经常做的变更操作是水平扩容,就是增加Redis集群的节点数量来达到扩容的目的,这个水平扩容操作就会涉及到key的迁移,把原实例上的key迁移到新扩容的实例上。当要对key进行迁移时,是通过migrate命令来完成的,migrate实际上是通过dump + restore + del三个命令组合成原子命令完成,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生才会释放:迁移成功,迁移失败,等待超时。


如果key的迁移过程中遇到Bigkey,会长时间阻塞进行迁移的两个实例,可能造成客户端阻塞,导致客户端访问超时;也可能迁移时间太长,造成迁移超时导致迁移失败,水平扩容失败。

用户评论