项目历史悠久,迭代多年,经过众多同事接手。对于缓存的使用存在许多不合理之处,导致了许多keys冗余: 目前项目采用了128G的集群,八台实例,平均内存占用70-80G,大概2亿个key。Redis的费用非常昂贵,贴一张阿里云相近规格收费的图。 大key会带来的问题如下: 1、集群模式在slot分片均匀情况下,会出现数据和查询倾斜情况,部分有大key的Redis节点占用内存多,QPS高。 2、大key相关的删除或者自动过期时,会出现qps突降或者突升的情况,极端情况下,会造成主从复制异常,Redis服务阻塞无法响应请求。 基于以上原因,需要对项目的缓存进行优化。 谈到缩容,最直接的方法肯定是分析出占用内存最大的key,对其进行优化。从此处开始,文章中提到的大key不单指单个大key,类似几百万数据的hash集合;也包含了一类key的占用了较大的空间,例如实例存在1000万个 user:info:{userid} 的string类型的key,我们也将它称为大key。 列举分析常用的样本采集方案 方案 优缺点 是否选用 bigkeys命令 优点:使用简单 缺点:耗时较长,只能统计五种基础数据,无法对一类key名称进行匹配,只能找出单个大key 否 在单台实例执行bgSave,dump下来对应的RDB文件,使用对应的分析工具进行分析。我们使用的是rdb_bigkeys 优点:对业务不造成影响,本地数据,随时可以进行分析 缺点:时效性较弱 是 扫描脚本,使用scan命令配合扫描整台实例的keys 优点:支持任意数据类型,时效性高 缺点:虽然scan命令不阻塞主线程,但是大范围扫描keys还是会加重实例的IO,可以闲时再执行。 否 分析keys的使用,对于时效性要求肯定是不高的,所以选用了方案2,分析RDB文件,并定位key的影响范围。截取部分分析结果图: 分析出了大key后,就可以按keys的占用空间来排序,从前往后按优先级归纳需要优化的keys。项目中keys存在的问题在最开始已经总结过。 对于不合理的keys,我们分为两类: 一、需要优化改进的keys 这就需要针对业务场景做针对性处理了,只能给出一些典型例子的建议: 二、可以直接删除的keys 对于可以直接删除的keys,建议使用scan命令+unlink命令删除,避免主线程阻塞。我们采用的删除方式是:scan轮流扫描各个实例,匹配需要删除的Keys。 风险点: 大家都知道对于客户端命令的执行,Redis是单线程处理的,所以存在一些阻塞主线程的操作风险: 三、优化了许多keys,内存占用还是很高,怎么回事? Redis日常的使用是会存在内存碎片的,可在客户端执行info memory命令。如果mem_fragmentation_ratio值大于1.5,那么说明内存碎片超过50%,需要进行碎片整理了 解决方案: 删除掉一批弃用的keys后,Redis内存占用已经减少了10G。代码上的优化由于业务需求,有些key零散地设置了2-3个月的过期时间,两三个月过后刚好又迎来了淡季,无法准确预估优化了多少空间,但是总归还是有一定的成果。过程的思路和方案仅供参考。一、需求背景
1.1背景
1.2优化的原因
1.2.1昂贵的费用
1.2.2大key存在的隐患
二、优化思路
2.1分析key的使用情况
2.1.1key的采集与分析
2.1.2优化方案
三、优化成果