对于任何一个应用服务和组件,都需要一个完整可靠的监控解决方案。尤其是像redis这样的敏感纯内存、高并发、低延迟的服务,完善的监控告警方案是实现精细化运营的前提。本文分几个部分详细阐述Redis的监控告警:1.Redis监控告警的价值2.Redis监控的数据采集3.Redis告警策略4.基于OpenFalcon的Redis监控告警的价值Redis监控告警方案Redis监控告警每个角色的取值都不一样,主要有几个重要的方面:redis故障的快速通知,以及故障点的定位;对于DBA来说,需要快速发现、定位和解决redis的可用性和性能故障。分析redis故障根源Redis容量规划与性能管理Redis硬件资源利用率与成本快速发现redis故障,定位故障点并排除故障当redis发生故障时,DBA应在最短时间内发现告警;如果故障影响服务有损(如大规模网络故障或程序BUG),需要立即通知SRE和RD启动故障预案(如切换机房或开启应急开关)止损。如果没有完善的监控和报警;假设RD发现了一个服务故障,然后查看整个服务调用链来定位;即使用户发现问题,通过客服投诉,再排查redis故障的问题;整个redis故障的发现、定位和解决时间被拉长了,原本的一个故障被“无限”放大了。分析redis故障的根本原因任何故障和性能问题往往只有一个根本原因,称为故障根本原因。一个故障从DBA发现、止损、分析定位、解决方案,以及后续规避措施开始;最重要的是DBA通过各种问题表象层层分析根源;只有找到问题的根源,才能根治此类问题,避免再次发生。完善的redis监控数据是我们分析根因的依据和依据。备注:排查病根,就像医生通过病人的病历和检查报告,找到“真正的病灶”,让病人康复,减少痛苦一样,既有趣又复杂;真相同样令人震惊。(再看DBA吹牛),其实在大型商业系统中,一次故障直接损失很容易达到几十万(间接损失更大),所以“抓住罪魁祸首”,防患于未然。犯罪”又是同一个“破案”。问题的表现是综合性的,一般可能性比较复杂。这里有两个例子:服务调用Redis响应时间的性能总是在增加;可能是网络问题,redis查询慢,redisQPS提升达到性能瓶颈,redisfork阻塞和Request排队,redis使用swap,cpu达到饱和(单核idle太低),aoffsync阻塞,网络导入和export资源饱和等,Redis使用内存突然增加,很快达到maxmemory;可能写的key很大,key的数量增长,某类key的平均长度突然变长,forkCOW,client输入/输出缓冲区,lua程序占用等。根本原因是监控数据和凭直觉取证,而不是有技术支持的推理分析。Redis响应抖动,分析定位到rootcause为bgsave,fork导致阻塞200ms的例子。而不是分析推理:redis进程rss达到30gb,响应抖动应该有同步。fork子进程时,复制页表时必须阻塞父进程。预估页表大小为xx,根据内存连续复制1m数据需要xx纳秒。分析叉子阻塞的可能原因。(这种分析是不需要的)解释:粮厂在分析根本原因时,有一个习惯,就是尽可能多地获取视觉证据。因为推理步骤一旦引入,每一步的推理结果都可能出现偏差,最终可能给出错误的根本原因。“罪魁祸首”又跑了,估计下一次的罪名会更大。因此,建议对于任何小的过错或抖动,至少从个人内部或群体内部,深入分析,找出根源;这样,个人或组织就会成长得更快;就会形成良好的氛围。Redis容量规划与性能管理分析redis资源使用历史趋势数据及性能指标监控;合理扩容(Scale-out)和缩容(Scale-back)集群;优化性能瓶颈等Redis资源使用饱和度监控,设置合理的阈值;一些常用的容量指标:redis内存使用率、swap使用率、cpu单核饱和度等;当资源使用容量被警告时,可以及时扩展,避免资源过载。造成故障。另一方面,如果资源利用率持续过低,及时通知业务,进行redis集群缩容处理,避免资源浪费。并且通过redis容器化管理,系统可以根据监控数据自动灵活扩缩容。Redis性能监控和管理可以及时发现性能瓶颈,优化或扩容,将问题扼杀在“萌芽期”,防止其“演化”成故障。Redis硬件资源利用率和成本在老板看来,最关心的是成本和资源利用率是否达标。资源不达标,要推进资源优化整合;提高硬件利用率,减少资源浪费。削减预算并削减成本。通过监控系统收集资源利用率是否达标的数据。在这一部分,有很多话要说;只是强调redis并不是只有一个端口存活监控。下面进入正题,如何采集redsis监控数据。老大曾说过:监控告警和数据备份是对DBA和SRE最基本也是最高的要求;当服务和存储达到产品规模时,可以认为是“无监控,无服务;无备份,无存储”。Redis监控数据采集Redis监控数据采集,一分钟采集一次数据,分为以下几个方面:服务器系统数据采集Redis服务器数据采集Redis响应时间数据采集Redis监控屏幕服务器系统监控数据采集服务器系统数据采集,这部分包含数百个指标。采集方式现在监控平台自带的agent都会支持,比如Zabbix、OpenFalcon,采集方式这里就不介绍了。我们从redis使用资源的特点来分析各个子系统的重要监控指标。服务器生存监控ping监控告警CPU平均负载(LoadAverage):综合负载指标(暂归为cpu子系统),当系统的子系统过度使用时,平均负载会增加。可以解释redis的处理性能下降(平均响应时间变长,吞吐量下降)。CPU整体利用率或饱和度(cpu.busy):redis中高并发或高时间复杂度的指令会使整体CPU资源饱和,导致redis性能下降,请求堆积。CPU单核饱和(cpu.core.idle/core=0):redis是单进程模式。通常,只使用一个cpu核心。单实例存在cpu性能瓶颈,导致性能失败。但是一般有24个线程的系统CPU饱和度很低。所以监控cpu单核利用率也是一样的。CPU上下文切换次数(cpu.switches):上下文切换过高xxxxxxmemoryandswapsystemmemorymarginsize(mem.memfree):redis是纯内存系统,系统内存必须有足够的margin,避免OOM,导致在redis进程中被杀掉,或者使用swap导致redis的性能急剧下降。系统swap使用大小(mem.swapused):只要redis的“热数据”进入swap,redis的处理性能就会急剧下降;无论交换分区是否为SSD介质。操作系统用于交换的材料仍然是磁盘存储。这也是笔者前期使用redis实现VM,后来放弃的原因。说明:系统内存余量合理,各种buffer和forkcow都有足够的内存空间。还有一个问题:我的系统使用的是Redis缓存集群,“不怕挂,就怕慢”,或者redis集群高可用;redis服务器可以通过这种方式关闭swap吗?磁盘分区使用率(df.bytes.used.percent):磁盘空间使用监控告警,保证有足够的磁盘空间使用AOF/RDB,日志文件存储。但是redis服务器一般很少出现磁盘容量问题。磁盘IOPS饱和(disk.io.util):如果有AOF持久化,注意这种情况。如果AOF持续存在,每秒都会积累同步,这可能会导致写入停顿。另外,磁盘的顺序吞吐量还是很重要的。如果太低,在复制同步RDB时会延长同步RDB的时间。(expectdisklessreplication)Networkthroughputsaturation(net.if.out.bytes/net.if.in.bytes):如果服务器是千兆网卡(速度:1000Mb/s),出现异常情况单机多实例key容量大导致网卡流量爆满。redis的整体服务下降了相同的数量,并且遭受了故障转移。丢包率:影响Redis服务响应质量RedisServer监控数据采集通过redis实例的状态数据采集,采集监控数据的命令有ping,infoall,slowlogget/len/reset/clusterinfo/configgetRedis生存监控redis生存监控(redis_alive):redis本地监控代理使用ping。如果指定时间返回PONG表示存活,否则redis无法响应请求,可能阻塞或死亡。Redis正常运行时间监控(redis_uptime):uptime_in_secondsRedis连接数监控连接数(connected_clients):客户端连接数,连接数过高会影响redis的吞吐量。一般建议不要超过5000。参考官方benchmarksconnectionusagerate(connected_clients_pct):连接使用百分比,按(connected_clients/macclients)计算;如果达到1,redis开始拒绝创建新连接。127.0.0.1:6380>setmykeymyvalue(error)ERRmaxnumberofclientsreached127.0.0.1:6380>拒绝连接数(rejected_connections):redis连接数达到maxclients限制,新连接数被拒绝。新建连接数(total_connections_received):如果新建连接过多,过多的创建和销毁连接会对性能产生影响,说明短连接严重或者连接池的使用有问题。有必要调查代码的连接设置。列表阻塞调用的阻塞连接数(blocked_clients):从未使用过BLPOP之类的命令。如果监控数据大于0,建议排查原因。Redis内存监控redis分配的内存大小(used_memory):Redis实际使用内存,没有内存碎片;单实例内存大小不建议太大,一般在10~20GB以内。Redis内存使用率(used_memory_pct):分配内存的百分比,由(used_memory/maxmemory)计算;对于redis的存储场景,会比较关注。如果不设置淘汰策略(maxmemory_policy),当达到maxmemory限制时不能写入数据。127.0.0.1:6380>setmykeymyvalue(error)OOMcommandnotallowedwhenusedmemory>'maxmemory'.127.0.0.1:6380>redis进程已用内存大小(used_memory_rss):进程实际使用的物理内存大小,包括内存碎片;如果rss过大,会造成内部碎片大,内存资源浪费,耗时的fork和cow内存也会增加。Redis内存碎片率(mem_fragmentation_ratio):表示(used_memory_rss/used_memory),碎片率过大,造成内存资源浪费;注意:1.如果内存占用小,mem_fragmentation_ratio可以远大于1,这个报警值不好设置。请参考used_memory大小。2、如果mem_fragmentation_ratio小于1,说明redis已经使用了swap分区Redis综合性能监控RedisKeyspace键(keys)的个数:redis实例包含的键的个数。建议控制在1kw以内;单实例key数量过多,可能导致过期key回收不及时。设置带生存时间(keys_expires)的key的个数:如果是纯缓存或者业务过期时间比较长的,建议给key设置TTL;避免业务中出现死键问题。(expiresfield)estimatetheaveragelifeofthesettime-to-livekey(avg_ttl):Redis会采样估算实例中设置TTLkey的平均时长,单位毫秒。如果没有TTLkey或者在Slave中,avg_ttl始终为0LRU逐出键数(evicted_keys):因为used_memory达到maxmemory限制,设置了一个逐出策略的实例;(对故障排除很重要,不必设置告警)expiredevictedkeysNumber(expired_keys):删除存活时间为0的key个数;包括主动删除和定期删除的次数。RedisqpsRedis处理的命令数(total_commands_processed):监控采集周期内的平均qps。Redis单实例处理量达到数万。如果请求过多,redis过载会导致请求堆积。Redis的当前qps(instantaneous_ops_per_sec):redis内部实时每秒执行的命令数;它可以作为total_commands_processed监控的补充。Rediscmdstat_xxx这段说明,redis记录了所有执行过的命令;通过infoall的Commandstats部分收集数据。每种命令执行的次数(cmdstat_xxx):这个值对于分析redis抖动变化很有用。如下表示:每条命令执行次数,总消耗CPU时间(单位微秒),平均每次消耗CPU时间(单位微秒)#Commandstatscmdstat_set:calls=6,usec=37,usec_per_call=6.17cmdstat_lpush:calls=4,usec=32,usec_per_call=8.00cmdstat_lpop:calls=4,usec=33,usec_per_call=8.25Rediskeysapce命中率redis键空间请求命中率监控,通过这个监控衡量redis缓存的好坏,如果miss率或者次数高,可能是由于热数据大于redis的内存限制,导致请求落到后端存储组件,可能需要扩展redis缓存集群的内存容量。当然也有可能是业务特性造成的。请求键命中次数(keyspace_hits):redis请求键被命中的次数。请求键未命中次数(keyspace_misses):redis请求键未命中的次数;也会有很多点击量。可以参考Baron写的WhyyoushouldignoreMySQL'skeycachehitratio。请求key的命中率(key??space_hit_ratio):使用keyspace_hits/(keyspace_hits+keyspace_misses)计算,这是衡量Redis缓存服务好坏的标准。Redisforkredis执行BGSAVE、BGREWRITEAOF命令,redis进程有fork操作。而且fork会对redis进程有一个短暂的冻结,这个冻结redis无法响应任务请求。因此,监控fork的阻塞时间非常重要。如果你的系统不能接受redis的500ms阻塞,那么就需要监控fork阻塞时间的变化,进行容量规划。Thenumberofmicrosecondsblockedbythelatestfork(latest_fork_usec):最近一次fork操作阻塞redis进程所花费的时间,单位为微秒。Redis网络流量Redis一般部署在单机多实例上。当服务器网络流量大幅增加时,需要快速定位到是哪个redis实例消耗了网络流量;另外,如果redis的写流量过大,可能会导致slave线程对“clientoutputbuffer”的堆积,当达到限制时,连接被Maser强行断开,出现复制中断。因此,我们需要对每个redis实例的网络进出口流量进行监控,并设置合适的告警值。说明:网络监控指标,只有高版本才有,应该在2.8.2x之后redis网络入口流量字节数(total_net_input_bytes)redis网络出口流量字节数(total_net_output_bytes)redis网络入口kps(instantaneous_input_kbps)redis网络出口kps(instantaneous_output_kbps)第一个两个是累计值,根据监控平台一个采集周期(比如一分钟)内每秒的平均流量字节数计算。Redis慢查询监控Redis慢查询是排查性能问题的关键监控指标。因为redis是单线程服务器模型(single-threadedserver),即一次只能执行一个命令。如果该命令耗时较长,则其他命令会被阻塞,进入队列排队等待;这将极大地影响程序的性能。Redis慢查询存储在内存中,最多可以保存slowlog-max-len(默认128)条慢查询命令。当慢查询命令日志达到128条时,在添加新的慢查询之前,最旧的慢查询命令将被删除。因为慢查询无法持久化,无法实时监控每秒产生多少慢查询。我们推荐的慢查询监控方式:设置合理的慢查询日志阈值,slowlog-log-slower-than,建议为1ms(如果平均为1ms,redisqps只有1000)设置完整的慢查询日志队列长度,slowlog-max-len建议大于1024。因为监控采集周期为1分钟,建议避免删除慢查询日志;另外,当慢查询参数过多时,会被省略,内存消耗很小。使用slowloglen获取每次集合的慢查询日志使用slowlogget1024获取每次的慢查询,并转移到其他地方,如MongoDB或MySQL,方便排错;并分析当前慢查询日志最长耗时微秒。然后使用slowlogreset清除慢查询日志,下一个采集周期的日志长度为最新的。redis慢查询的监控项:redis慢查询日志条数(slowlog_len):每个采集周期内的慢查询条数,比如1分钟大于1ms的慢查询10条,redisslow最长耗时值querylogs(slowlog_max_time):获取慢查询的最长耗时值,因为一些小于10秒的慢查询可能会导致复制中断,甚至出现主从切换等故障。Redis持久化监控redis存储场景的集群,所以需要redis持久化来保证数据落地,减少故障时的数据丢失。这里分析redisrdb数据持久化的几个监控指标。最新的rdb是否持久化成功(rdb_last_bgsave_status):如果持久化不成功,建议告警,说明备份或主从复制同步不正常。或者redis设置为"stop-writes-on-bgsave-error"为yes,当save失败时,会导致redis无法写入最后一次成功的rdbfilegenerationinseconds(rdb_last_bgsave_time_sec):rdbgenerationtime-consumedresponsesynchronization数据是否在一段时间内增长;如果远程备份使用redis-cli–rdb方式远程备份rdb文件,时间长短可能会影响备份线程客户端使用的输出缓冲内存大小。自上次成功生成rdb文件以来的写命令数(rdb_changes_since_last_save):即有多少写命令没有被持久化,最坏情况下会丢失的写命令数。建议设置监控告警距离最后一次RDB持久化成功的秒数(rdb_last_save_time):最坏情况下数据写入丢失的秒数。使用当前时间戳——收集到的rdb_last_save_time(最后一次成功的rdb持久化的时间戳),计算多少秒没有成功生成rdb文件Redis复制监控无论使用什么redis集群方案,都会使用redis复制。复制相关的监控告警项:redis角色(redis_role):实例的角色,是master还是slave复制连接状态(master_link_status):slave端可以查看它与master的同步状态;当replication断开时,就意味着down了,影响集群当前的Availability。需要设置监控告警。复制连接断开时间长度(master_link_down_since_seconds):主从服务器同步断开的秒数。建议设置一个时间闹钟。主库有多少秒没有给从库发送数据(master_last_io_seconds):如果主库超过repl-timeout秒没有给从库发送命令和数据,会导致replication断开重连。详细分析见文章:Redis复制中断与无限同步问题。可以在slave端进行监控。建议设置闹钟10秒以上。多少秒没有向主库发送REPLCCONF命令(slave_lag):正常情况下,从库每秒向主库发送一个REPLCONFACK命令;如果从库因为某种原因,命令没有上报给主库,主从复制有中断的风险。通过在master端监控每个slave的滞后值。是否设置从库只读(slave_read_only):默认从库只读,禁止写操作,监控从库的只读状态;如果关闭只读从库,则存在写入数据的风险。关于主从数据不一致,见文章中的分析:Redis不复制主从数据-主库挂载的从库数量(connected_slaves):主库保证至少有一个从库,以及不建议设置超过2个从数据库。是否启用replicationbacklogbuffer(repl_backlog_active):主库默认启用replicationbacklogbuffer,用于应对短期复制中断,使用部分同步方式。复制积压缓冲区大小(repl_backlog_size):主库复制积压缓冲区的默认大小为1MB。由于redis服务器共享一个buffer,建议设置100MB。注意:关于根据实际情况设置合适大小的replicationbuffer。您可以使用master_repl_offset指标来计算每秒写入的字节数,并将其乘以您要使用“部分同步”方法的秒数。Redis集群监控这里写的redis官方集群方案的监控指标数据,基本都是通过clusterinfo和info命令收集的。实例是否开启集群模式(cluster_enabled):通过info的cluster_enabled监控集群模式是否开启。集群健康状态(cluster_state):如果当前redis发现失败的slots,默认将其cluster_state由ok改为fail,write命令会失败。如果将cluster-require-full-coverage设置为NO,则没有此限制。集群数据槽slots的分配(cluster_slots_assigned):集群正常运行时,默认有16384个slots。下线的数据槽槽数(cluster_slots_fail):当集群正常运行时,应该为0,如果大于0,说明集群中有槽失效。集群中分片数(cluster_size):集群中设置的分片数集群中节点数(cluster_known_nodes):集群中redis节点数Redis响应时间监控响应时间是衡量的一个重要指标服务组件的性能和质量。使用redis的服务通常对响应时间非常敏感,比如要求99%的响应时间在10ms以内。因为redis的慢查询日志只计算命令的CPU使用时间,没有考虑排队等其他耗时。最大响应时间(respond_time_max):最大响应时间(以毫秒为单位)99%响应时间长度(respond_time_99_max):99%平均响应时间长度(respond_time_99_avg):95%响应时间长度(respond_time_95_max):95%平均响应时间长度(respond_time_95_avg):建议监控响应时间,最简单的方法是使用Perconatcprstat
