相关文章推荐
火星上的葡萄酒  ·  Database In-Memory | ...·  6 月前    · 
激动的充值卡  ·  mysql ...·  1 年前    · 
文雅的炒饭  ·  VS ...·  1 年前    · 

在使用Redis的过程中,如果未能及时发现并处理Big keys(下文称为“大Key”)与Hotkeys(下文称为“热Key”),可能会导致服务性能下降、用户体验变差,甚至引发大面积故障。本文将介绍大Key与热Key产生的原因、其可能引发的问题及如何快速找出大Key与热Key并将其优化的方案。

大Key和热Key的定义

  • QPS集中在特定的Key:Redis实例的总QPS(每秒查询率)为10,000,而其中一个Key的每秒访问量达到了7,000。
  • 带宽使用率集中在特定的Key:对一个拥有上千个成员且总大小为1 MB的HASH Key每秒发送大量的 HGETALL 操作请求。
  • CPU使用时间占比集中在特定的Key:对一个拥有数万个成员的Key(ZSET类型)每秒发送大量的 ZRANGE 操作请求。
  • Redis内存达到 maxmemory 参数定义的上限引发操作阻塞或重要的Key被逐出,甚至引发内存溢出(Out Of Memory)。
  • 集群架构下,某个数据分片的内存使用率远超其他数据分片,无法使数据分片的内存资源达到均衡。
  • 对大Key执行读请求,会使Redis实例的带宽使用率被占满,导致自身服务变慢,同时易波及相关的服务。
  • 对大Key执行删除操作,易造成主库较长时间的阻塞,进而可能引发同步中断或主从切换。
  • 占用大量的CPU资源,影响其他请求并导致整体性能降低。
  • 集群架构下,产生访问倾斜,即某个数据分片被大量访问,而其他数据分片处于空闲状态,可能引起该数据分片的连接数被耗尽,新的连接建立请求被拒绝等问题。
  • 在抢购或秒杀场景下,可能因商品对应库存Key的请求量过大,超出Redis处理能力造成超卖。
  • 热Key的请求压力数量超出Redis的承受能力易造成缓存击穿,即大量请求将被直接指向后端的存储层,导致存储访问量激增甚至宕机,从而影响其他业务。
  • 在不适用的场景下使用Redis,易造成Key的value过大,如使用String类型的Key存放大体积二进制文件型数据;
  • 业务上线前规划设计不足,没有对Key中的成员进行合理的拆分,造成个别Key中的成员数量过多;
  • 未定期清理无效数据,造成如HASH类型Key中的成员持续不断地增加;
  • 使用LIST类型Key的业务消费侧发生代码故障,造成对应Key的成员只增不减。
  • 预期外的访问量陡增,如突然出现的爆款商品、访问量暴涨的热点新闻、直播间某主播搞活动带来的大量刷屏点赞、游戏中某区域发生多个工会之间的战斗涉及大量玩家等。
  • 可实时展示实例中的大Key和热Key信息,同时支持查看4天内大Key和热Key的历史信息。该功能可帮助您掌握Key在内存中的占用、Key的访问频次等信息,溯源分析问题,为您的优化操作提供数据支持。 离线全量Key分析
  • 优点:可对历史备份数据进行分析,对线上服务无影响。
  • 缺点:时效性差,RDB文件较大时耗时较长。
  • 对Redis的RDB备份文件进行定制化的分析,帮助您发现实例中的大Key,掌握Key在内存中的占用和分布、Key过期时间等信息,为您的优化操作提供数据支持,帮助您避免因Key倾斜引发的内存不足、性能下降等问题。 通过redis-cli的 bigkeys hotkeys 参数查找大Key和热Key
  • 优点:方便、快速、安全。
  • 缺点:分析结果不可定制化,准确性与时效性差。
  • Redis提供了 bigkeys 参数能够使redis-cli以遍历的方式分析Redis实例中的所有Key,并返回Key的整体统计信息与每个数据类型中Top1的大Key, bigkeys 仅能分析并输入六种数据类型(STRING、LIST、HASH、SET、ZSET、STREAM),命令示例为 redis-cli -h r-***************.redis.rds.aliyuncs.com -a <password> --bigkeys
    说明 若您只需要分析STRING类型的大key或是找出成员数量超过10个的HASH Key,则 bigkeys 参数无法直接实现该类需求。

    同时,自Redis 4.0版本起提供了 hotkeys 参数,可以快速帮您找出业务中的热Key,具体操作,请参见 通过redis-cli的hotkeys参数查找热Key 。 对不同数据类型的目标Key,分别通过如下风险较低的命令进行分析,来判断目标Key是否符合大Key判定标准。

  • STRING类型:执行 STRLEN 命令,返回对应Key的value的字节数。
  • LIST类型:执行 LLEN 命令,返回对应Key的列表长度。
  • HASH类型:执行 HLEN 命令,返回对应Key的成员数量。
  • SET类型:执行 SCARD 命令,返回对应Key的成员数量。
  • ZSET类型:执行 ZCARD 命令,返回对应Key的成员数量。
  • STREAM类型:执行 XLEN 命令,返回对应Key的成员数量。
  • 对大Key进行拆分

    例如将含有数万成员的一个HASH Key拆分为多个HASH Key,并确保每个Key的成员数量在合理范围。在Redis集群架构中,拆分大Key能对数据分片间的内存平衡起到显著作用。

  • 对大Key进行清理
    将不适用Redis能力的数据存至其它存储,并在Redis中删除此类数据。
  • Redis 4.0及之后版本:您可以通过 UNLINK 命令安全地删除大Key甚至特大Key,该命令能够以非阻塞的方式,逐步地清理传入的Key。
  • Redis 4.0之前的版本:建议先通过 SCAN 命令读取部分数据,然后进行删除,避免一次性删除大量key导致Redis阻塞。
  • 监控Redis的内存水位

    您可以通过监控系统设置合理的Redis内存报警阈值进行提醒,例如Redis内存使用率超过70%、Redis的内存在1小时内增长率超过20%等。通过此类监控手段,可以提前规避许多问题,例如LIST数据类型的消费程序故障造成对应Key的列表数量持续增长,将告警转变为预警从而避免故障的发生,更多信息,请参见 报警设置

  • 对过期数据进行定期清理
    堆积大量过期数据会造成大Key的产生,例如在HASH数据类型中以增量的形式不断写入大量数据而忽略了数据的时效性。可以通过定时任务的方式对失效数据进行清理。
    说明 在清理HASH数据时,建议通过 HSCAN 命令配合 HDEL 命令对失效数据进行清理,避免清理大量数据造成Redis阻塞。
  • 使用阿里云的Tair服务(Redis企业版)避开失效数据的清理工作

    若HASH Key过多,存在大量的成员失效需要被清理的问题,又由于大量Key与大量失效数据叠加,无法通过定时任务对无效数据进行及时地清理,您可以通过阿里云Tair服务高效地解决此类问题。

    Tair是云数据库Redis的企业版,它具备Redis所有特性(包括Redis的高性能特点),同时提供了大量额外的高级功能。

    TairHash是一种可为field设置过期时间和版本的HASH数据类型,它不但和Redis Hash一样支持丰富的数据接口和高处理性能,还改变了Hash只能为Key设置过期时间的限制,可以为field设置过期时间和版本。这极大地提高了HASH数据类型的灵活性,简化了很多场景下的业务开发工作。同时,TairHash使用高效的Active Expire算法,实现了在对响应时间几乎无影响的前提下,高效完成对field过期判断和删除的功能。

    此类高级功能的合理使用能够解放大量Redis的运维、故障处理工作并降低业务的代码复杂度,更多信息,请参见 TairHash命令

  • 在Redis集群架构中对热Key进行复制
    在Redis集群架构中,由于热Key的迁移粒度问题,无法将请求分散至其他数据分片,导致单个数据分片的压力无法下降。此时,可以将对应热Key进行复制并迁移至其他数据分片,例如将热Key foo复制出3个内容完全一样的Key并名为foo2、foo3、foo4,将这三个Key迁移到其他数据分片来解决单个数据分片的热Key压力。
    说明 该方案的缺点在于需要联动修改代码,同时带来了数据一致性的挑战(由原来更新一个Key演变为需要更新多个Key),仅建议该方案用来解决临时棘手的问题。
  • 使用读写分离架构

    如果热Key的产生来自于读请求,您可以将实例改造成读写分离架构来降低每个数据分片的读请求压力,甚至可以不断地增加从节点。但是读写分离架构在增加业务代码复杂度的同时,也会增加Redis集群架构复杂度。不仅要为多个从节点提供转发层(如Proxy,LVS等)来实现负载均衡,还要考虑从节点数量显著增加后带来故障率增加的问题。Redis集群架构变更会为监控、运维、故障处理带来了更大的挑战。

    然而,阿里云Redis服务以开箱即用的方式提供服务。在业务发生变化时,您仅需通过变配的方式调整实例架构来轻松应对,例如将主从架构转变为读写分离架构、将读写分构架构转变为集群架构,以及将社区版转变为支持大量高级特性的Tair版(Redis企业版)等,更多信息,请参见 变更实例配置

    说明 读写分离架构同样存在缺点,在请求量极大的场景下,读写分离架构会产生不可避免的延迟,此时会有读取到脏数据的问题。因此,在读、写压力都较大且对数据一致性要求很高的场景下,读写分离架构并不是最优方案。
  • 使用阿里云Tair的QueryCache特性

    云数据库Redis会根据高效的排序和统计算法识别出实例中存在的热点Key(通常热点Key的QPS大于3,000),开启该功能后,代理节点Proxy会根据设定的规则缓存热点Key的请求和查询结果(仅缓存热点Key的查询结果,无需缓存整个Key)。当在缓存有效时间内收到相同的请求时,Proxy会直接返回结果至客户端,无需和后端的数据分片执行交互。在提升读取速度的同时,降低了热点Key对数据分片的性能影响,避免访问倾斜。

    开通该功能后,来自客户端的同样请求无需再与Proxy后端的Redis进行交互而是由Proxy直接返回数据,指向热Key的请求由一个Redis节点承担转为多个Proxy共同承担,能够大幅度降低Redis节点的热Key压力。同时Tair的QueryCache功能还提供了大量的命令来方便您查看、管理代理查询缓存的情况,例如通过 querycache keys 命令查看所有被缓存热Key,通过 querycache listall 命令获取所有已缓存的所有命令等。更多信息,请参见 通过Proxy Query Cache优化热点Key问题

  •