昨天凌晨,因为占用容量峰值为 218 G,DBA 将 Redis 的容量由 500G 调低到了 320G。在调低容量后,Redis 开始频繁报 HighMemoryUsage
的警告。而查看 Redis 集群的监控后发现,总容量用掉的比例不足 60%,不应该频繁报警,因此开始了排查之路。
排查原因
首先,我们已经排除了是总容量大小的问题。
由于我们的 Redis 是阿里云的集群版,有多个节点,因此我查看了各个节点的大小。果然,最大的节点已经超过 90%,而小的节点的占用则在 30% 左右。这说明 Redis 发生了非常严重的倾斜。
我们现有的程序已经充分考虑到了 Redis 集群的特性,key
设计策略没有问题,不应该出现如此大的倾斜,所以问题在其他方面。
我们用阿里云的 python 脚本来查询 Redis 大 key,果真发现有一些很老的废弃的大 key,key 为 hash 类型,每个的长度在 500 万以上,最长的接近 1000 万。因此,倾斜的原因是这些大 key 的存在,且这些大 key 在不同节点分布不均匀。
找出大 key
由于阿里云的 python 脚本非常慢,因此我写了一个 golang 的脚本来查找大 key。
因为阿里云集群版 Redis 做了一些改造,因此需要使用 iscan
命令(阿里云Redis命令列表)。
1 | for i := 0; i < 32; i++ { |
在这里,如果发现了应该删除的小 key ,我们直接删掉,并将大 key 找了出来。
删除大 key
因为 Redis 的特性,删除大 key 可能会导致线程阻塞,其他请求无法接收造成应用闪崩。因此我需要将大 key 的元素逐步清空,再移除这个 key(在 Redis 4.0 以上版本中,可以直接使用 unlink 命令另外启动一个线程来删除大 key)。
1 | for { |
这样便完成了大 key 的删除。
总结
在确定 Redis 分布不均匀后,我们要首先检查是否是有大 key,如果有的话要逐步清除,不能影响业务。之后需要选择合适的方案设计 Redis key,使其均匀的分布在各个节点。