目录
背景
热Key和大Key的概念
产生的原因
检测大KEY和热KEY的主要方法
解决方法
背景
在redis的使用过程中如果出现了大Key和热Key的问题将会影响用户的体验,会导致服务的性能下降、甚至造成大面积故障。本文将介绍大Key与热Key产生的原因,以及如何去检测和优化大Key和热Key。
热Key和大Key的概念
所谓的大key就是指Key的大小过大或者Key中成员的数量过多的key,大Key的出现多是由于主键设置不合理,使得单个分区的记录数或数据量过大。
那么多大才算大Key呢?一般我们认为符合以下条件的可以认定为大Key。
- Key本身的数据量过大:一个String类型的Key,它的值为5 MB。
- Key中的成员数过多:一个ZSET类型的Key,它的成员数量为10,000个。
- Key中成员的数据量过大:一个Hash类型的Key,它的成员数量虽然只有1,000个但这些成员的Value(值)总大小为100 MB。
热Key指的是QPS特别集中的key,我们就把他称之为热key。
- 单个key的qps占总的实例QPS的比例超过百分之65我们就认为这个key属于热key。比如Redis实例的总QPS(每秒查询率)为10,000,而其中一个Key的每秒访问量达到了7,000。
- 带宽使用率集中在特定的Key:对一个拥有上千个成员且总大小为1 MB的HASH Key每秒发送大量的HGETALL操作请求。
- CPU使用时间占比集中在特定的Key:对一个拥有数万个成员的Key(ZSET类型)每秒发送大量的ZRANGE操作请求。
产生的原因
未正确使用Redis、业务规划不足、无效数据的堆积、访问量突增等都会产生大Key与热Key,如:
大key
- 在不适用的场景下使用Redis,易造成Key的value过大,如使用String类型的Key存放大体积二进制文件型数据;
- 业务上线前规划设计不足,没有对Key中的成员进行合理的拆分,造成个别Key中的成员数量过多;
- 未定期清理无效数据,造成如HASH类型Key中的成员持续不断地增加;
- 使用LIST类型Key的业务消费侧发生代码故障,造成对应Key的成员只增不减。
热key
- 预期外的访问量爆增,如某某明星出轨的热点话题的出现或者主播做活动商品秒杀这类的访问量突发性的增加。
- 用户消费的数据远大于生产的数据,如商品秒杀、热点新闻、热点评论等读多写少的场景。
- 请求分片集中超过单台的性能
检测大KEY和热KEY的主要方法
1、可以凭借业务经验对热Key进行预判
比如在秒杀活动开始前秒杀商品的信息的key一般会成为热点key;但每次的预测不可能都那么的精确,还要结合商家之前数据进行判断。
2、使用redis自带的命令来检测大Key和热Key
Redis的MONITOR命令能够忠实地打印Redis中的所有请求,包括时间信息、Client信息、命令以及Key信息。不过这种方法会占用CPU、内存、网络资源,时效性与准确性较差。
通过redis-cli的bigkeys和hotkeys参数查找大Key和热Key。Redis提供了bigkeys参数能够使redis-cli以遍历的方式分析Redis实例中的所有Key,并返回Key的整体统计信息与每个数据类型中Top1的大Key,bigkeys仅能分析并输入六种数据类型(STRING、LIST、HASH、SET、ZSET、STREAM)。redis 4.0.3提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可;但是该参数在执行的时候,如果key比较多,执行起来比较慢。
3、加入对Key使用情况的进行统计
- 实时TopKey统计
准确性高、对性能几乎无影响。展示的Key数量有一定限制,但能满足常规场景下的需求。
- 离线全量Key统计
可对历史备份数据进行分析,对线上服务无影响。不过他的时效性较差,耗时较长。
4、上报Proxy层对热Key进行处理
云数据库Redis会根据高效的排序和统计算法识别出实例中存在的热点Key(通常热点Key的QPS大于3,000),开启该功能后,代理节点Proxy会根据设定的规则缓存热点Key的请求和查询结果(仅缓存热点Key的查询结果,无需缓存整个Key)。当在缓存有效时间内收到相同的请求时,Proxy会直接返回结果至客户端,无需和后端的数据分片执行交互。在提升读取速度的同时,降低了热点Key对数据分片的性能影响,避免访问倾斜。
解决方法
对于热Key:
1、在Redis集群架构中对热Key进行复制
可以将对应热Key进行复制并迁移至其他数据分片,例如将热Key foo复制出3个内容完全一样的Key并名为foo2、foo3、foo4,将这三个Key迁移到其他数据分片来解决单个数据分片的热Key压力。
2、使用读写分离架构
如果热Key的产生来自于读请求,您可以将实例改造成读写分离架构来降低每个数据分片的读请求压力,甚至可以不断地增加从节点。但是读写分离架构在增加业务代码复杂度的同时,也会增加Redis集群架构复杂度。
3、使用Proxy层对热key进行处理
配置参数:
query_cache_enabled:0:不启用,默认值。1:启用。
query_cache_mode:0:只缓存数据分片推送的热点Key的查询结果,默认值。1:缓存所有Key的查询结果并进行根据最近最少使用算法LRU(Least Recently Used)进行淘汰。
query_cache_expire:缓存数据的有效时间,单位为毫秒,取值:100~60000,默认值为1000。
开启该功能后,代理节点Proxy会根据设定的规则缓存热点Key的请求和查询结果(仅缓存热点Key的查询结果,无需缓存整个Key)。当在缓存有效时间内收到相同的请求时,Proxy会直接返回结果至客户端,无需和后端的数据分片执行交互。在提升读取速度的同时,降低了热点Key对数据分片的性能影响,避免访问倾斜。
4、使用二级缓存
即JVM本地缓存,直接从本地中拿,而不会去访问集群。
对于大Key:
1、对大Key进行拆分
例如将含有数万成员的一个HASH Key拆分为多个HASH Key,并确保每个Key的成员数量在合理范围。在Redis集群架构中,拆分大Key能对数据分片间的内存平衡起到显著作用。
2、对大Key进行清理
将不适用Redis能力的数据存至其它存储,并在Redis中删除此类数据。
3、监控Redis的内存水位
例如LIST数据类型的消费程序故障造成对应Key的列表数量持续增长,将告警转变为预警从而避免故障的发生。
4、对过期数据进行定期清理
堆积大量过期数据会造成大Key的产生,例如在HASH数据类型中以增量的形式不断写入大量数据而忽略了数据的时效性。可以通过定时任务的方式对失效数据进行清理。