Redis 的 BigKey、HotKey 又引发了线上事故!( 三 )

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

Redis 的 BigKey、HotKey 又引发了线上事故!

文章插图
 
可以使用 Daas 平台“工具集-操作项管理”,选择对应的 slave 实例执行分析,找出具体的 Bigkey 。
问题2:超时阻塞Redis 是单线程工作的,通俗点讲就是同一时间只能处理一个 Redis 的访问命令,
操作 Bigkey 的命令通常比较耗时,这段时间 Redis 不能处理其他命令,其他命令只能阻塞等待,这样会造成客户端阻塞,导致客户端访问超时,更严重的会造成 master-slave 的故障切换 。
当然,造成阻塞的操作不仅仅是业务程序的访问,还有 key 的自动过期的删除、del 删除命令,对于 Bigkey,这些操作也需要谨慎使用 。
来一个生产上的超时阻塞案例我们遇到一个这样超时阻塞的案例,业务方反映:程序访问 Redis 集群出现超时现象,hkeys 访问 Redis 的平均响应时间在 200 毫秒左右,最大响应时间达到了 500 毫秒以上,如下图 。
 
Redis 的 BigKey、HotKey 又引发了线上事故!

文章插图
 
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 情况 。
 
Redis 的 BigKey、HotKey 又引发了线上事故!

文章插图

Redis 的 BigKey、HotKey 又引发了线上事故!

文章插图
 
2.使用 Daas 平台“工具集-操作项管理”,选择 slave 实例执行分析,分析结果如下图,有一个 hash 类型 key 有 12102218 个 fields 。
 
Redis 的 BigKey、HotKey 又引发了线上事故!

文章插图
 
  1. 和业务沟通,进行Bigkey 拆分这个 Bigkey 是连续存放了 30 天的业务数据了,建议根据二次 hash 方式拆分成多个 key,也可把 30 天的数据根据分钟级别拆分成多个 key,把每个 key 的元素数量控制在 5000 以内 。优化后,监控指标的响应时间的突刺就会消失了 。
问题3:网络阻塞Bigkey 的 value 比较大,也意味着每次获取要产生的网络流量较大,假设一个 Bigkey 为 10MB,客户端每秒访问量为 100,那么每秒产生 1000MB 的流量,对于普通的千兆网卡(按照字节算是 128MB/s)的服务器来说简直是灭顶之灾 。
而且我们现在的 Redis 服务器是采用单机多实例的方式来部署 Redis 实例的,也就是说一个 Bigkey 可能会对同一个服务器上的其他 Redis 集群实例造成影响,影响到其他的业务 。
问题4:迁移困难我们在运维中经常做的变更操作是水平扩容,就是增加 Redis 集群的节点数量来达到扩容的目的,这个水平扩容操作就会涉及到 key 的迁移,把原实例上的 key 迁移到新扩容的实例上 。
当要对 key 进行迁移时,是通过 migrate 命令来完成的,migrate 实际上是通过 dump + restore + del 三个命令组合成原子命令完成,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生才会释放:迁移成功,迁移失败,等待超时 。
如果 key 的迁移过程中遇到 Bigkey,会长时间阻塞进行迁移的两个实例,可能造成客户端阻塞,导致客户端访问超时;也可能迁移时间太长,造成迁移超时导致迁移失败,水平扩容失败 。
来一个生产上的迁移失败案例我们也遇到过一些因为 Bigkey 扩容迁移失败的案例,如下图所示,
这是一个 Redis 集群水平扩容的工单,需要进行 key 的迁移,当工单执行到 60%的时候,迁移失败了 。


推荐阅读