作者: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 以上了。
能够应用应用 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,会长工夫阻塞进行迁徙的两个实例,可能造成客户端阻塞,导致客户端拜访超时;也可能迁徙工夫太长,造成迁徙超时导致迁徙失败,程度扩容失败。
迁徙失败案例
咱们也遇到过一些因为 Bigkey 扩容迁徙失败的案例,如下图所示,是一个 Redis 集群程度扩容的工单,须要进行 key 的迁徙,当工单执行到 60% 的时候,迁徙失败了。
1. 进入工单找到失败的实例,应用失败实例的 slave 节点,在 Daas 平台的“工具集 - 操作项治理”进行 Bigkey 剖析。
2. 通过剖析找出了 hash 类型的 Bigkey 有 8421874 个 fields,正是这个 Bigkey 导致迁徙工夫太长,超过了迁徙工夫限度,导致工单失败了。
3. 和业务沟通,这些 key 是记录用户拜访零碎的某个功能模块的 ip 地址的,拜访该功能模块的所有 ip 都会记录到给 key 外面,随着工夫的积攒,这个 key 变的越来越大。同样是采纳拆分的形式进行优化,能够思考依照工夫日期维度来拆分,就是一段时间段的拜访 ip 记录到一个 key 中。
4.Bigkey 优化后,扩容的工单能够重试,实现集群扩容操作。
三、Bigkey 的发现
Bigkey 首先须要重源头治理,避免 Bigkey 的产生;其次是须要可能及时的发现,发现后及时处理。剖析 Bigkey 的办法不少,这里介绍两种比拟罕用的办法,也是 Daas 平台剖析 Bigkey 应用的两种形式,别离是 Bigkeys 命令分析法、RDB 文件分析法。
3.1 scan 命令剖析
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 发现能力。
参考资料:
- Redis 命令参考
- Github:rdb-tools
- redis 之 bigkey(看这一篇就够)