【巡检问题分析与最佳实践】Redis CPU高问题

往期分享

RDS MySQL

RDS MySQL 实例空间问题

RDS MySQL 内存使用问题

RDS MySQL 活跃线程数高问题

RDS MySQL 慢SQL问题

RDS MySQL 实例IO高问题

RDS MySQL 小版本升级最佳实践

RDS PostgreSQL

RDS PostgreSQL 实例IO高问题

RDS PostgreSQL 慢SQL问题

RDS PostgreSQL CPU高问题

RDS SQL Server

RDS SQL Server 磁盘IO吞吐高问题

RDS SQL Server CPU高问题

RDS SQL Server 空间使用问题

Redis

Redis 流控问题

Redis 内存高问题

概述

默认情况下,社区版Redis使用单线程模型处理读写请求,这使得CPU的使用率显得尤为重要。当实例的CPU打满时会导致数据库响应缓慢,严重影响线上业务。

本文将由浅入深帮您查看、分析和优化云数据库Redis的CPU使用率。

查看CPU使用

    部署架构为主备模式下,只提供当前主节点的CPU使用。通过监控图查看CPU的使用率非常方便,点击控制台"性能监控"后一目了然。

【巡检问题分析与最佳实践】Redis CPU高问题

部署架构为Redis集群/读写分离模式下,由于多个物理节点组成了一个逻辑实例,且可能通过多个Proxy节点做路由转发和负载均衡,通过监控图查看CPU使用率时一般只需要关注该集群数据节点的CPU使用率,"数据节点聚合指标","Proxy节点聚合指标","Proxy"中的CPU使用率请忽略。【巡检问题分析与最佳实践】Redis CPU高问题

CPU使用率高的一般排查步骤

    由于社区版Redis6.0以下的版本使用单线程处理IO请求,所以基本上Redis进程本身也只能用到CPU的一个核,当CPU使用率超过80%时,就需要引起开发者的高度重视。一般可以大概分为以下几个步骤

确认是否存在流量突增/热点Key

    在没有明显慢SQL的情况下,读写流量突增是引起Redis High CPU的常见原因,云数据库Redis不同的产品形态和实例规格对应了不同的QPS上限。

详情建议参考:

  但需要注意的,这里提供的结果仅仅作为基准压测的参考,在实际的生产环境中,某个Redis实例能够承载的QPS上限往往与key和value的平均长度,key的数据类型,内网带宽等息息相关。也就是说,当前Redis实例的处理能力上限要以实际的业务压测为准,当业务代码没有任何变动的情况下CPU突增,建议您结合监控图先观察当前Redis实例的各项QPS指标是否同样存在突增。

另外阿里云支持Redis热点key的实时和历史情况查看,详细可参考:

   如果纯粹是由于业务增长/热点Key引起的Redis CPU使用率高,那么优化思路一般有以下几种,本质上就是通过多线程或者架构升级的方式解决:

  • 进行业务拆分,不同的业务使用不同的Redis实例
  • 针对一些hash结构的超热点key(单key请求过10w),可以考虑将其拆分成string类型并存放至多个Redis实例中
  • 针对string类型的超热点key(单key写请求过10w),在业务架构无法限流的情况下,必须使用阿里云“性能增强版”,多线程IO处理模型可以抗住20w以上的单key请求量
  • 针对读多写少的场景,可以考虑使用阿里云Redis读写分离版,通过添加只读实例的方式抗住高并发读请求
  • 针对写多读少的场景,可以考虑使用阿里云Redis集群版,注意使用读写分离/集群版以后,可能存在少部分Redis命令的兼容性

    我们做一下简单对比,比如阿里云Redis社区标准版能够承载的QPS为K(社区标准版性能基本上与社区开源保持一致,基准压测的情况下一般在10w左右),如下表格即为阿里云主流Redis产品形态下的读写QPS总数参考。

Redis社区版

集群

Redis社区版

读写分离

Redis企业版-性能增强型主备

Redis企业版-性能增强型集群

Redis企业版-性能增强型读写分离

写(key均匀情况)

K*分片数

K

K*3

K*3*分片数

K*3

读(key均匀情况)

K*分片数

K*只读节点数

K*3

K*3*分片数

K*3*只读节点

写(热key)

K(最坏情况)

K

K*3

K*3

K*3

读(热key)

K(最坏情况)

K*只读节点数

K*3

K*3

K*3*只读节点

确认是否存在慢SQL

    在阿里云数据库Redis中,默认执行时间超过20ms的称为慢SQL,会记录到慢SQL FIFO队列以供查看。查询执行时间指的是不包括像客户端响应(talking)、发送回复等 IO 操作,而单单是执行一个查询命令所耗费的时间,您可以通过控制台提供的参数slowlog-log-slower-than和slowlog-max-len自定义配置慢SQL阈值和保存条数。您可以通过Redis自带得slowlog get指令查看慢SQL,也可以通过阿里云控制台CloudDBA查看,详细内容请参考:

    通常Redis指令消耗的CPU与指令的时间复杂度息息相关,一般认为O(N)或以上的复杂度在业务代码设计时需要谨慎对待它对应的流量评估。具体每个Redis指令的时间复杂度请参考官方文档:https://redis.io/commands

    最常见的慢SQL包括KEYS LRANGE EVAL HGETALL PUBSUB等,一般都是扫描量比较大,KEY比较大,涉及到Redis计算逻辑的指令,这些较为消耗CPU资源的指令详情和原理请参考:

    由于Redis提供有相对较多的数据类型,而诸如Hash,List等常见数据类型中列表长度上限较高,所以在实际使用中很容易导致big key问题,阿里云Redis控制台CloudDBA提供有"缓存分析"找出实例中的存在性能隐患的大Key,详情可参考:https://help.aliyun.com/document_detail/102093.html

确认是否存在流量不均

    在使用读写分离/集群架构模式下,当集群出现响应延迟时,首先需要确认是集群下所有对外提供服务的物理节点均出现High CPU还是部分节点出现热点的情况。

    除了上述提到的big key和热点key容易引起的集群数据倾斜和流量不均以外,还有几种情况可能导致读写分离架构下的各个主节点,只读节点之间的流量不均:

  • scan系列命令由于存在上下文关系,需要将该类命令全部转发至第一个只读节点
  • bitfield命令混合了读写属性,默认情况下只会转发至主节点,这点阿里云Redis已优化,可提工单开启,详细参考:https://zhuanlan.zhihu.com/p/139747397

通用最佳实践

关于以上可能引起的CPU打满的情况,通用的最佳实践有以下几点:

  • 优先设计合理的数据结构和逻辑,各指令的流量评估,并进行实际的业务压测。
  • 尽量不要使用pubsub做消息订阅和分发,Redis实际上并不适合。
  • 尽量避免使用lua做事务,脚本编译和加载会非常消耗CPU,建议使用扩展数据结构代替,如果需要实现高性能分布式锁建议使用企业版Redis,详细可参考:https://help.aliyun.com/document_detail/146758.html
  • Hash结构不适合存放通质且大量的key,容易引起数据倾斜并造成big key问题。
  • 尽量避免使用blocking的API,如blpop,brpop等。
  • 尽量避免keys命令的模糊匹配,当数据量上涨后一定会出现问题,建议使用scan命令代替,针对危险命令可以在控制台禁用,详细可参考:https://help.aliyun.com/document_detail/107695.html

特殊场景下的High CPU

在一些特殊情况下,Redis也会更加消耗CPU,我们在实际运维的过程中一般有遇到以下情况:

  • 节点宕机导致的全量同步,期间存在部分对外服务节点无法提供读负载均衡。
  • Redis超高频使用incr指令作为计数器应用时,master节点CPU使用率可能比slave高很多,因为master向slave传输数据时可能做了合并,类似于pipeline,所以slave节点需要回放的请求数更少,消耗的CPU更低。
  • 高频建连操作可能消耗更多的CPU,因为连接的建立和释放均会消耗一定的CPU,建议使用连接池,或者升级至Proxy集群,企业性能增强版等Redis产品。
  • 在连接数较多的情况下频繁调用info指令查看各项监控信息可能导致CPU使用率更高,因为部分info子命令的监控信息统计需要遍历每一个client连接,所以当连接数超过5k的情况下建议控制info的频率。
  • 频繁的AOF可能导致更高的CPU消耗,如果是将Redis纯粹当作Cache使用的场景,建议关闭AOF持久化,详细参考:https://redis.io/commands/bgrewriteaof






上一篇:RDS MySQL Adaptive Hash Index (AHI)最佳实践


下一篇:【巡检问题分析与最佳实践】MongoDB 磁盘IO高问题