一、说说什么是Redis、及特点?
Redis是一个基于内存存储数据运行并支持持久化、使用key/value形式存储的高性能的nosql数据库,适合用于存储频繁访问,数据量较小的场景下。
特点:
- 支持数据持久化:可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
- 支持多种数据结构:不仅支持简单的key-value类型数据,同时还提供string、list、set、zset、hash等数据结构的存储
- 支持数据备份:master-salve模式的数据备份
二、什么是大key
通常我们会将含有较大数据或含有大量成员、列表数的Key称之为大Key,下面我们将用几个实际的例子对大Key的特征进行(量化)描述:
- 一个STRING类型的Key,它的值为5MB(数据过大)
- 一个LIST类型的Key,它的列表数量为20000个(列表数量过多)
- 一个ZSET类型的Key,它的成员数量为10000个(成员数量过多)
- 一个HASH格式的Key,它的成员数量虽然只有1000个但这些成员的value总大小为100MB(成员体积过大)
三、什么是热Key
在某个Key接收到的访问次数、显著高于其它Key时,我们可以将其称之为热Key,常见的热Key如:
- 某Redis实例的每秒总访问量为10000,而其中一个Key的每秒访问量达到了7000(访问次数显著高于其它Key)
- 对一个拥有上千个成员且总大小为1MB的HASH Key每秒发送大量的HGETALL(带宽占用显著高于其它Key)
- 对一个拥有数万个成员的ZSET Key每秒发送大量的ZRANGE(CPU时间占用显著高于其它Key)
四、大Key与热Key带来的问题
在Redis的使用中,大Key及热Key会给Redis带来各种各样的问题,而最常见的问题为性能下降、访问超时、数据不均衡等。
4.1 大Key带来的常见问题
- Client发现Redis变慢;
- Redis内存不断变大引发OOM,或达到maxmemory设置值引发写阻塞或重要Key被逐出;
- Redis Cluster中的某个node内存远超其余node,但因Redis Cluster的数据迁移最小粒度为Key而无法将node上的内存均衡化;
- 大Key上的读请求使Redis占用服务器全部带宽,自身变慢的同时影响到该服务器上的其它服务;
- 删除一个大Key造成主库较长时间的阻塞并引发同步中断或主从切换;
4.2 热Key带来的常见问题
- 热Key占用大量的Redis CPU时间使其性能变差并影响其它请求;
- Redis Cluster中各node流量不均衡造成Redis Cluster的分布式优势无法被Client利用,一个分片负载很高而其它分片十分空闲从而产生读/写热点问题;
- 在抢购、秒杀活动中,由于商品对应库存Key的请求量过大超出Redis处理能力造成超卖;
- 热Key的请求压力数量超出Redis的承受能力造成缓存击穿,此时大量强求将直接指向后端存储将其打挂并影响到其它业务;
五、大Key与热Key的常见产生原因
业务规划不足、Redis不正确的使用、无效数据的堆积、访问突增等都会产生大Key与热Key,如:
- 将Redis用在并不适合其能力的场景,造成Key的value过大,如使用String类型的Key存放大体积二进制文件型数据(大Key);
- 业务上线前规划设计考虑不足没有对Key中的成员进行合理的拆分,造成个别Key中的成员数量过多(大Key);
- 没有对无效数据进行定期清理,造成如HASH类型Key中的成员持续不断的增加(大Key);
- 预期外的访问量陡增,如突然出现的爆款商品、访问量暴涨的热点新闻、直播间某大主播搞活动带来的大量刷屏点赞、游戏中某区域发生多个工会间的战斗涉及大量玩家等(热Key);
- 使用LIST类型Key的业务消费侧代码故障,造成对应Key的成员只增不减(大Key);
六、找出Redis中的大Key与热Key
大Key与热Key的分析并不困难,我们有多种途径和手段来对Redis中的Key进行分析并找出其中的“问题”Key,如Redis的内置功能、开源工具、阿里云Redis控制台中的Key分析功能等。
七、大key的处理方法
大key的处理方法有两种:
- 拆分
- 删除
拆分:
如将一个成员很多的hash拆分为多个hash。
删除:
将不适合Redis能力的数据存放至其它存储,并在Redis中删除此类数据。需要注意的是,删除大key可能很耗时,redis又是单线程执行的,很可能造成阻塞,Redis自4.0起提供了UNLINK命令,该命令能够异步的方式安全的删除大Key。
八、热key的处理方法
热key的处理方法有两种:
- 复制
- 读写分离
- 多级缓存
复制:
在使用redis集群时,可以将热key复制多份,每个redis节点上存放一份,这样不存在请求的重定向使得压力全部定向到单个节点,能有效减轻单节点的压力。缺点是要进行复制的画只能在代码层手动操作,而且复制多份存放后会存在数据一致性问题。因此复制方案只能用于临时解决线上问题。
读写分离:
热key多数是读热key的操作,读写分离能保证从节点中数据的一致性,并且能轻松的横向扩展,能有效的分散压力,只是有点浪费资源,因为读写分离每个从节点上存的都是一样的数据。
多级缓存:
当热key数量不多,比如电商平台促销活动,热key都集中在少部分key上面,为此做读写分离增加机器性价比不高,使用多级缓存是个不错的解决方法。具体实现思路两种:
1.本地缓存,redis和业务服务器之间增加一个中间层(proxy),专门用来进行热key探查,这个proxy专门用来监视redis来统计达到预设的热key阈值的key,统计好后推送给业务服务器,让业务服务器存在本地缓存。
2.单独缓存,将proxy探查到的热key推送到单独的一个缓存热key的redis上去,如果扛不住,热key服务器再横向扩容,当然这个方案也是单独增加了服务器结点去处理热key的,除非保证系统中经常会有热key出现,不然的话使用本地缓存性价比更高。
使用多级缓存会存在一个问题,因为每次推送之间有时间间隔,缓存中的数据和redis中的数据不是呈现强一致性的,而是呈现最终一致性的。这种代价也是不得不接受的,在使用缓存的时候注意不要拿缓存做逻辑,只用来做查询即可。