某天晚上突然收到redis集群内存使用率超过80%的告警,观察内存使用率曲线,发现该集群内存相对平稳,之前一直维持在70%左右,遂申请新机器进行扩容,新节点添加完成之后,集群整体内存使用率降至50%,但是由于集群本身数据量巨大,集群内部数据迁移需要较长时间。
数据迁移一直持续到次日下午还没完成,此时已经有不少节点没来得及迁移数据使用率已经超过90%了,整体内存也又出现了高于80%的告警,且数据量依然持续增长没有减缓的趋势,虽然集群有配置数据淘汰策略violatelru,但是由于数据量巨大,过多淘汰还是会对后端存储带来冲击,事态发展的有些不可控了。
紧急与业务方同事一起组织电话会议攻关:
1.首先考虑到的是业务近期有什么操作,能否把变更回退掉,但是却被告知近一个月业务都没有变更
2.查看集群访问TPS发现确实一直很平稳,没有异常变化
3.查看集群key数量,没有发现明显增长
4.怀疑会不会被其他业务误操作了,通过client cist查看,没有其他业务的连接
5.怀疑业务的key异常变大了(翻倍级别),随即选取一个节点分析rdb文件,发现较多集合类型的key,集合元素数量业务方确认也没有倍数增大
6.重点放在对集合类型的key的数据结构分析上,使用object encoding key命令查询key的编码格式,发现接类型的key均为hashtable
7.查阅资料继续攻关,发现集合类型的key编码格式在intset和hashtable下使用的内存差异巨大,检查集群配置config get set-max-intset-entries,发现默认使用512,scard 查询集合元素数,发现刚才抽查的类型为hashtable的key的元素个数都在512以上,且刚刚超过512没多少,与集群数据量增长时间吻合
量 | key大小 | value大小 | 编码 | 集合长度 | 内存量 | 内存降低比例 | 平均耗时 |
---|---|---|---|---|---|---|---|
100w | 20byte | 7字节 | hashtable | 1千 | 61.97MB | – | 0.78毫秒 |
100w | 20byte | 7字节 | intset | 1千 | 4.77MB | 92.6% | 0.51毫秒 |
8.为验证分析结果,将大于512元素的key删除一部分元素,使元素数小于512,再次使用object encoding查看,发现仍然为hashtable,查询资料得知,小的编码类型往大的编码类型转换可以自动进行,且非常快速,但是大的编码类型不会随着元素数减少恢复为小的编码类型,增大set-max-intset-entries配置项的值也一样无效
9.所以为了尽快解决容量问题,避免数据淘汰风险,且优化集群内存使用,我们先将现网配置项set-max-intset-entries调整到1024,然后出工具把set备份删除重新写入,测试了一个节点,发现数据量下降50%左右,验证通过,问题得到解决
由于现网之前没有出现过类似案例,开发运维同事都没有调优该参数的经验,导致问题定位耗时较长,这里把经验分享出来,希望后面的同事少走弯路。
参考:
https://www.jianshu.com/p/82b1f6fe5444
《Redis开发与运维》一书第八章