要进行Redis的故障定位,一般通过分析 Redis日志应用日志Redis的监控信息来定位相关问题。

# 一、Redis 日志设置

【1】日志文件: Redis默认日志在控制台打印,启动时即可看到对应日志打印到控制台上。建议修改 redis.config 的默认配置:[logfile ""],为其指定记录日志的文件[logfile "/usr/redis/log/redis.log"]。重启项目发现启动日志已经从控制台转到日志文件中了。

【2】日志级别: Redis日志分为4个级别:debugverbosenoticewarning 默认为notice(生产一般使用此模式)

debug:会打印出很多信息,适用于开发和测试阶段
verbose(冗长的):包含很多不太有用的信息,但比debug要清爽一些
notice:适用于生产模式
warning:警告信息

【3】日志问题排查 : ①、当Redis出现问题时,想通过Redis日志定位问题时,首先应查看Redis文件,确定日志的具体位置。②、分析日志内容,根据日志的具体内容,分析、定位问题。

# 二、Redis 的几个重要健康指标

【0】慢日志: ①、通过命令[slowlog get]得到Redis执行的slowlog集合,理想情况下slowlog集合应该为空即没有任何慢日志。②、若发现有慢命令,则应该逐个分析是否正常,是否需要优化。

【1】存活情况:是最重要的健康指标,通过命令PING的响应是否为PONG来判断。

【2】连接数: ①、连接的客户端数量,[redis-cli info Clients|grep connected_clients] 得到,这个值与使用Redis服务的连接池配置关系比较大,这个值如果很大,需要排查问题原因。②、另外还有一个拒绝连接数(rejected_connections)也需要关注,这个值理想状态是 0 。如果大于 0,说明创建的连接数大于maxclients,需要排查原因。是Redis连接池配合不合理还是连接这个Redis 的服务过多。

【3】阻塞客户端数量: blocked_clients 通常是执行了 list 数据类型的BLPOP或者BRPOP命令引起的,可以通过[redis-cli info Clients|grep blocked_clients]得到,这个值最应该=0。

【4】使用内存峰值: ①、监控Redis内存使用峰值,可以通过命令[config set maxmemory]设置允许使用的最大内存。②、为了防止发生swap导致Redis性能骤减,甚至由于使用内存超标导致系统kill,建议used_memory_peak(占用内存的峰值)的值与maxmemory的值有个安全区间,例如1G。

【5】内存碎片率:
 ①、mem_fragmentation_ratio = used_memory_rss/use_memory当值大于1时,表示分配的内存超过实际使用的内存,数值越大[利用率不高],碎片率越严重。当这个值小于1时,表示发生了 swap(Swap分区在系统的物理内存不够用的时候,把物理内存中的一部分空间释放出来,以供当前运行的程序使用) ,既可用内存不足。
 ②、Redis4.0有一个主要的特性就是优化内存碎片率问题(Memory defragmentation)。在redis.conf 配置文件中[ACTIVE DEFRAGMENTATION:碎片整理允许Redis压缩内存空间,从而回收内存。此特性默认是关闭的,可以通过命令CONFIG SET activedefrag yes热启动这个特性]。
 ③、当内存使用量(use_memory)很小的时候,这个值参考价值不大。所以建议used_memory至少 1G 以上才考虑对内存碎片率进行监控。

【6】缓存命中率: ①、keyspace_misses/keyspace_hits这两个指标用来统计缓存的命中率,keyspace_misses值未命中次数,keyspace_hits表示命令次数。keyspace_hits/(keyspace_misses+keyspace_hits) 就是缓存命中率。②、如果缓存命中率过低,那么要排查对缓存的用法是否有问题。

【7】OPS instantaneous_pos_per_sec 表示缓存的OPS(operation per second 每秒操作次数)

【8】持久化: ①、rdb_last_bgsave_status/aof_last_bgrewrite_status,即最近一次或者最后一次 RDB/AOF 持久化是否有问题,这两个值都应该时 “OK”。②、由于Redis持久化时会fork子进程,且 fork是一个完全阻塞的过程,所以可以监控fork耗时即:latest_fork_usec,单位是微妙,如果这个值比较大会影响业务,甚至出现 timeout 。

【9】失效KEY 如果把Redis当缓存使用,那么建议所有的key都设置expire属性,通过命令redis-cli info Keyspace得到每个 db 中key的数量和设置了expire属性的key的属性,且 expires(表示设置了超时时间的key个数) 需要等于keys

# 三、验证/修复RDB和AOF持久化文件

【1】redis-check-dump:目前无法修复出错的快照文件,因为快照文件本身进行了压缩。快照中的错误可能会导致剩余部分无法访问。将重要的快照进行多次备份,在后期的恢复中通过计算数据的SHA1散列和 SHA256 散列对内容进行验证。

【2】redis-check-aof:运行redis-check-aof --fix程序对aof文件进行修复。扫描aof文件,找到第一个出错的命令,并且删除出错命令及后续所有命令。一般情况下,被删除的都是aof文件末尾的不完整命令。

# 四、案例实战分析

【1】案例一现象: 生产系统刚开始运行阶段,系统稳定。但是运行了一段时间后,发现部分时间段系统接口响应变慢。查看客户端日志经常会出现如下错误:

redis.clients.jedis.exception.JedisConnectionException:java.net.SocketTimeoutException:Read time out
1

【问题定位】: 执行slowlog查看慢查询日志,发现大量的keys命令操作,keys命令在大量并发情况下性能非常差,生产环境,尽量避免使用keys,接下来找出使用keys的代码做优化,直到time out问题解决。

【2】案例二现象: 生产环境长时间的运行后,经常会有接口返回数据失败的情况,或者是从监控上发现数据库压力某一时间暴增。查看客户端日志发现如下错误:

redis.clients.jedis.exceptions.JedisConnectionException:Cloud not get a resource from the pool
1

【问题定位】: 执行client list命令,发现大量的clientidle时间特别长。检查配置发现timeouttcp-keepalive(心跳检测) 均未启用(均为0),Redis服务端没有有效的机制来确保连接是否已经失效。当服务器与客户端网络发生闪断,导致tcp中断,这种情况下的client将会一直被redis服务端所持有,就会出现idle(空闲)时间特长的client连接。解决办法:设置timeouttcp-keepalive来清理失效的连接。

【3】案例三现象: Redis突然间不能访问,返回如下错误:

redis.client.jedis.exception.JedisDataException:MISCONF Redis is configured to save RDB snapshots,
but is currently not able to persist on disk.Commands that may modify the data set are disabled.
Please check Redis logs for details about the error
1
2
3

【问题定位】: 查看redis日志,发现如下错误:Cant save in background:fork:Cannot allocate memory Redis在保存内存的数据到磁盘时,为了防止主线程假死,会Fork 一个子进程来完成这个保存操作,这个Fork的子进程需要分配与主进程相同的内存,这时候就相当于需要的内存翻倍了。如果这时候可用内存不足以分配需要的内存,将会导致Fork子进程失败而无法将数据持久化到磁盘。修改Linux内核参数vm.overcommit_memeory=1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何) 问题便可解决。

(adsbygoogle = window.adsbygoogle || []).push({});