作者:vivo 互联网数据库团队- Du Ting

在Redis运维进程中,因为Bigkey 的存在,会影响事务程序的呼应速度,严峻的还会形成可用性丢失,DBA也一向和事务开发方着重 Bigkey 的躲避办法以及损害。

一、布景

在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以上了。

Bigkey问题的解决思路与方式探索

能够运用Daas渠道“东西集-操作项办理”,挑选对应的slave实例履行剖析,找出详细的Bigkey。

2.3.2 超时堵塞

Redis是单线程工作的,浅显点讲便是同一时刻只能处理一个Redis的拜访指令,操作Bigkey的指令通常比较耗时,这段时刻Redis不能处理其他指令,其他指令只能堵塞等待,这样会形成客户端堵塞,导致客户端拜访超时,更严峻的会形成master-slave的毛病切换。形成堵塞的操作不仅仅是事务程序的拜访,还有key的自动过期的删去、del删去指令,关于Bigkey,这些操作也需求慎重运用。

超时堵塞事例

咱们遇到一个这样超时堵塞的事例,事务方反映程序拜访Redis集群出现超时现象,hkeys拜访Redis的平均呼应时刻在200毫秒左右,最大呼应时刻到达了500毫秒以上,如下图。

Bigkey问题的解决思路与方式探索

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状况。

Bigkey问题的解决思路与方式探索

Bigkey问题的解决思路与方式探索

2.运用Daas渠道“东西集-操作项办理”,挑选slave实例履行剖析,剖析成果如下图,有一个hash类型key有12102218个fields。

Bigkey问题的解决思路与方式探索

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,会长时刻堵塞进行搬迁的两个实例,或许形成客户端堵塞,导致客户端拜访超时;也或许搬迁时刻太长,形成搬迁超时导致搬迁失利,水平扩容失利。

搬迁失利事例

咱们也遇到过一些因为Bigkey扩容搬迁失利的事例,如下图所示,是一个Redis集群水平扩容的工单,需求进行key的搬迁,当工单履行到60%的时分,搬迁失利了。

1. 进入工单找到失利的实例,运用失利实例的slave节点,在Daas渠道的“东西集-操作项办理”进行Bigkey剖析。

Bigkey问题的解决思路与方式探索

2. 经过剖析找出了hash类型的Bigkey有8421874个fields,正是这个Bigkey导致搬迁时刻太长,超越了搬迁时刻约束,导致工单失利了。

Bigkey问题的解决思路与方式探索

3.和事务沟通,这些key是记载用户拜访体系的某个功用模块的ip地址的,拜访该功用模块的一切ip都会记载到给key里边,跟着时刻的堆集,这个key变的越来越大。同样是选用拆分的方法进行优化,能够考虑依照时刻日期维度来拆分,便是一段时刻段的拜访ip记载到一个key中。

4.Bigkey优化后,扩容的工单能够重试,完结集群扩容操作。

三、Bigkey的发现

Bigkey首先需求重源头管理,避免Bigkey的产生;其次是需求能够及时的发现,发现后及时处理。剖析Bigkey的办法不少,这里介绍两种比较常用的办法,也是Daas渠道剖析Bigkey运用的两种方法,别离是Bigkeys指令剖析法、RDB文件剖析法。

3.1 Bigkeys指令剖析

Redis4.0及以上版别供给了–Bigkeys指令,能够剖析出实例中每种数据结构的top 1的Bigkey,一起给出了每种数据类型的键值个数以及平均巨细。履行–Bigkeys指令时分需求注意以下几点:

  • 主张在slave节点履行,因为–Bigkeys也是经过scan完结的,或许会对节点形成堵塞。

  • 主张在节点本机履行,这样能够削减网络开销。

  • 假如没有从节点,能够运用–i参数,例如(–i 0.1 代表100毫秒履行一次)。

  • –Bigkeys只能核算每种数据结构的top1,假如有些数据结构有比较多的Bigkey,是查找不出来的。

Daas渠道集成了基于原生–Bigkeys代码完成的查询Bigkey的方法,这个方法的缺陷是只能核算每种数据结构的top1,假如有些数据结构有比较多的Bigkey,是查找不出来的。该方法相对比较安全,现已敞开出来给事务开发同学运用。

3.2 RDB文件剖析

凭借开源的东西,比方rdb-tools,剖析Redis实例的RDB文件,找出其间的Bigkey,这种方法需求生成RDB文件,需求注意以下几点:

  • 主张在slave节点履行,因为生成RDB文件会影响节点性能。

  • 需求生成RDB文件,会影响节点性能,虽然在slave节点履行,可是也是有或许形成主从中止,从而影响到master节点。

Daas渠道集成了基于RDB文件剖析代码完成的查询Bigkey的方法,能够依据实践需求自定义填写N,剖析的top N个Bigkey。该方法相对有必定风险,只要DBA有权限履行剖析。

3.3 Bigkey 巡检

经过巡检,能够暴露出危险,提早处理,避免毛病的产生,进行全网Bigkey的巡检,是避免Bigkey毛病的比较好的办法。因为全网Redis实例数量非常大,剖析的速度比较慢,运用当时的剖析办法很难完结。为了处理这个问题,存储研发组分布式数据库同学计划开发一个高效的RDB解析东西,然后经过大规模解析RDB文件来剖析Bigkey,能够提高剖析速度,完成Bigkey的巡检。

四、 Bigkey处理优化

4.1 Bigkey拆分

优化Bigkey的原则便是string削减字符串长度,list、hash、set、zset等削减元素数量。当咱们知道哪些key是Bigkey时,能够把单个key拆分红多个key,比方以下拆分方法能够参阅。

  • big list:list1、list2、…listN

  • big hash:能够做二次的hash,例如hash%100

  • 依照日期拆分多个:key20220310、key20220311、key202203212

4.2 Bigkey剖析东西优化

咱们全网Redis集群有2200以上,实例数量到达4.5万以上,有的比较大的集群的实例数量到达了1000以上,前面提到的两种Bigkey剖析东西还都是实例维度剖析,关于实例数量比较大的集群,进行全集群剖析也是比较耗时的,为了提高剖析效率,从以下几个方面进行优化:

  • 能够从集群维度挑选全部slave进行剖析。

  • 同一个集群的相同服务器slave实例串行剖析,不同服务器的slave实例并行剖析,最大并发度默认10,一起能够剖析10个实例,并且能够自定义输入履行剖析的并发度。

  • 剖析出契合Bigkey规则规范的一切key信息:大于1MB的string类型的一切key,假如不存在就列出最大的50个key;hash、list、set、zset等类型元素个数大于2000的一切key,如不存在就给出每种类型最大的50个key。

  • 添加暂停、重新开始、结束功用,暂停剖析后能够重新开始。

4.3 水平扩容搬迁优化

目前状况,咱们有一些Bigkey的发现是被迫的,一些是在水平扩容时分发现的,因为Bigkey的存在导致扩容失利了,严峻的还触发了master-slave的毛病切换,这个时分或许现已形成事务程序拜访超时,导致了可用性下降。

咱们剖析了Daas渠道的水平扩容时搬迁key的进程及影响参数,内容如下:

(1)【cluster-node-timeout】:操控集群的节点切换参数,master堵塞超越cluster-node-timeout/2这个时刻,就会片面判定该节点下线pfail状态,假如搬迁Bigkey堵塞时刻超越cluster-node-timeout/2,就或许会导致master-slave产生切换。

(2)【migrate timeout】:操控搬迁io的超时时刻,超越这个时刻搬迁没有完结,搬迁就会中止。

(3)【搬迁重试周期】:搬迁的重试周期是由水平扩容的节点数决定的,比方一个集群扩容10个节点,搬迁失利后的重试周期便是10次。

(4)【一个搬迁重试周期内的重试次数】:在一个起搬迁重试周期内,会有3次重试搬迁,每一次的migrate timeout的时刻别离是10秒、20秒、30秒,每次重试之间无距离。

比方一个集群扩容10个节点,搬迁时分遇到一个Bigkey,第一次搬迁的migrate timeout是10秒,10秒后没有完结搬迁,就会设置migrate timeout为20秒重试,假如再次失利,会设置migrate timeout为30秒重试,假如仍是失利,程序会搬迁其他新9个的节点,可是每次在搬迁其他新的节点之前还会别离设置migrate timeout为10秒、20秒、30秒重试搬迁那个搬迁失利的Bigkey。这个重试进程,每个重试周期堵塞(10+20+30)秒,会重试10个周期,共堵塞600秒。其实后边的9个重试周期都是无用的,每次重试之间没有距离,会接连堵塞了Redis实例。

(5)【搬迁失利日志】:搬迁失利后,记载的日志没有包括搬迁节点、solt、key信息,不能依据日志立即定位到问题key。

咱们对这个搬迁进程做了优化,详细如下:

(1)【cluster-node-timeout】:默认是60秒,在搬迁之前设置为15分钟,避免因为搬迁Bigkey堵塞导致master-slave毛病切换。

(2)【migrate timeout】:为了最大极限削减实例堵塞时刻,每次重试的超时时刻都是10秒,3次重试之间距离30秒,这样最多只会接连堵塞Redis实例10秒。

(3)【重试次数】:搬迁失利后,只重试3次(重试是为了避免网络抖动等原因形成的搬迁失利),每次重试距离30秒,重试3次后都失利了,会暂停搬迁,日志记载下Bigkey,去掉了其他节点搬迁的重试。

(4)【优化日志记载】:搬迁失利日志记载搬迁节点、solt、key信息,能够立即定位到问题节点及key。

五、总结

本文经过对Bigkey的剖析,要点介绍了在运维中对bigkey问题的处理思路、处理方法。首先是需求从源头管理,避免Bigkey形成,DBA应该加强对事务开发同学bigkey相关问题的宣导;其次是需求具备及时发现的才能,这个也是咱们现在的不足之处。咱们后边会从Bigkey巡检、Bigkey剖析东西的这两个方面,提高Bigkey发现才能。

参阅资料:

  1. Redis指令参阅

  2. Github:rdb-tools

  3. redis之bigkey(看这一篇就够)