一、使用slowlog识别慢查询
1.配置参数:slow-log-slower-than 设置一个非常小的值(5 微秒),意味着执行时间超过5微秒的操作会被慢日志记录下来。当选这个值为负时,表示禁用慢日志。
127.0.0.1:19000> CONFIG SET slow-log-slower-than 5
2.使用命令 SLOWLOG GET 来读取所有慢日志。
127.0.0.1:19000> SLOWLOG GET
3.使用命令 SLOWLOG LEN 获取慢日志中记录的数量。
127.0.0.1:19000> SLOWLOG LEN
(integer) 23
注意:redis的慢日志是只考虑了命令的实际执行时间,因为这个时间是服务器线程被阻塞且不能响应其他请求的时间。诸如磁盘I/O或网络传输的时间并不在考虑范围内。在这种情况下,瓶颈不是慢查询或慢操作,而是诸如网络延迟增加等其他因素
二、延迟问题分析
1. 基准延迟
基准延迟包括固有延迟和网络的往返延迟,固有延迟是是内核计划程序、虚拟机管理程序(如果是虚拟化实例)等所固有的,redis 无法超越内核。
- 使用 redis- cli intrinsic-latency <持续时间> 进行固有延迟测试(需要在redis服务器所运行的主机上运行):
$ redis-cli intrinsic-latency 60
Max latnecy so far:1 microseconds.
Max latnecy so far:14 microseconds
Max latnecy so far:85 microseconds
Max latnecy so far:130 microseconds
Max latnecy so far:137 microseconds
Max latnecy so far:140 microseconds
Max latnecy so far:660 microseconds
Max latnecy so far:1021 microseconds
1306392680 total runs (avg latency: 0.0459 microseconds / 45.93 nanoseconds per run).
Worst run took 22230x longer than the average latency.
- 使用 redis-cli 的latency 获取网络往返延迟(以每秒100次的速度向redis发送PING命令,并测量收到回复的时间):
$ redis-cli --latency
min: 0, max: 5, avg: 0.17(18107 samples)
以上示例中,延迟的基线是0.20(0.04+0.16)ms.
2. 生产环境监控redis延迟变化
参数 -i 是 每10秒重新开启一个测试会话
$ redis-cli --latency-history -i 10 >>latency.log &
$ tail -n10 latency.log
min: 0, max: 1, avg: 0.20 (956 samples) -- 10.00 seconds range
min: 0, max: 1, avg: 0.21 (956 samples) -- 10.00 seconds range
min: 0, max: 1, avg: 0.17 (956 samples) -- 10.00 seconds range
min: 0, max: 1, avg: 0.15 (956 samples) -- 10.00 seconds range
min: 0, max: 1, avg: 0.16 (956 samples) -- 10.00 seconds range
min: 0, max: 1, avg: 0.15 (956 samples) -- 10.00 seconds range
结果显示了最小(min)、最大(max)和平均延迟(avg)。
如果捕捉到了运行缓慢的内容,可以使用 INFO COMMANDSTATS 命令检查命令处理的相关统计信息:
127.0.0.1:19000> INFO COMMANDSTATS
# Commandstats
cmdstat_hmset:calls=10000000,usec=1018137090,usec_per_call=101.81
cmdstat_select:calls=10,usec=7,usec_per_call=0.7
cmdstat_dbsize:calls=7,usec=8,usec_per_call=1.14
cmdstat_info:calls=9,usec=307,usec_per_call=34.11
cmdstat_slowlog:calls=2,usec=51,usec_per_call=25.50
cmdstat_command:calls=4,usec=1012,usec_per_call=253.00
calls: 次数
usec: 总时间
usec_per_call:平均时间
结合INFO COMMANDSTATS 和 SLOWLOG 命令检查慢日志以定位究竟哪个命令处理得慢。若在上述步骤中发现了问题,需要考虑使用时间复杂度更低的操作来实现业务逻辑。
3. 检查CPU使用率
鉴于redis的单线程模型,核心的codis-server 进程只能使用服务器的一个核,因此,若codis-server 进程的CPU利用率接近100%,意味着redis实例已经超负荷。
- 检查cpu使用情况
$ ps aux |head -1;ps aux|grep codis-server
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2139 0.2 0.5 208024 40565 ? Ssl 2月20 27:45 /root/codis/../bin/codis-server 0.0.0.0:6379
另外,还可以检查下短时间内客户端的总连接数,如果该指标在短时间内急剧增加,也可能会导致客户端和服务端的延迟和服务端进程的CPU使用率过高。
4. 持久化
redis的持久化机制可能导致较高的磁盘I/O延迟。
(1)检查最近一次fork耗费的时间
生成RDB和AOF都需要父进程fork出一个子进程进行数据的持久化,在fork执行过程中,如果整个实例内存占用很大,那么需要拷贝的内存页表会比较耗时,此过程会消耗大量的CPU资源,在完成fork之前,整个实例会被阻塞住,无法处理任何请求,如果此时CPU资源紧张,那么fork的时间会更长,甚至达到秒级。
可以执行info命令,查看最后一次fork执行的耗时 latest_fork_usec,单位微秒
$ redis-cli -p 16379 -h 127.0.0.1 info |grep latest_fork
latest_fork_usec:1543
如果耗时很大, 比如超过1秒, 则需要做出优化调整:
- 关闭RDB和AOF的自动触发,避免业务高峰自动触发执行;
- 控制 Redis 实例最大可用内存;
- 合理配置 repl-backlog-size大小,降低主从全量重传;
- 尽量不要使用虚拟机,fork 的耗时也与系统也有关,虚拟机比物理机耗时更长。
(2)检查是否存在因AOF后台重写存在挂起的fsync任务
AOF重写是由后台子线程完成,但是AOF会有大量的IO操作,最终会和AOF的fsync进行磁盘的竞争;同时主线程会监控fsync的执行进度,若主线程在执行时候发现上一次的fsync操作还没有返回,那么主线程就会阻塞
检查指标 aof_delayed_fsync 是否正在增加,并检查指标 aof_pending_bio_fsync .
aof_delayed_fsync 一直在增加,说明主线程频繁出现被阻塞情况;aof_pending_bio_fsync 表示等待执行的fsync操作的数量。
遇到此种情况,可以考虑禁用AOF或appendfsync设置为none。
4. swap的检查
$ redis-cli -p 6379 info |grep process_id
process_id:2139
$awk '/VmSwap/{print $2 " " $3}' /proc/2139/status
0 KB
解决redis swap:
- 增大redis实例所在机器的内存。
- 集群部署的redis可以增加实例个数,减少每个实例所需要的内存。
- 把redis单独部署,不要和其他应用程序一起部署,也避免了cpu的竞争。
三、内存问题分析
- 检查redis实例存储的数据及大小是否超过了配置的maxmeory选项。
$ redis-cli info memory |egrep "used_memory_human| maxmemory_human"
used_memory_human:1023.40M
maxmemory_human:1.00G
- 若确认了内存问题,检查该问题的根本原因是大数据集导致的,还是不正常的内存使用导致的(若used_memory_dataset_perc>90%,说明是大数据集引起的):
$ reds-cli info memeory | egrep "used_memory_dataset|used_memory_dataset_perc"
used_memory_dataset:9808911121
used_memory_dataset_perc:92.11%
排除大数据集问题的方法是定位redis示例中的巨大键
$ redis-cli --bigkeys