共计 3310 个字符,预计需要花费 9 分钟才能阅读完成。
作者:任仲禹
爱可生 DBA 团队成员,善于故障剖析和性能优化,文章相干技术问题,欢送大家一起探讨。
本文起源:原创投稿
* 爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。
本文目录:
背景
- Redis 内存耗费划分
- 内存 OOM 会导致哪些问题?
排查思路
- 是否数据量太大?
- 是否客户端输出缓冲区有问题?
- 是否复制积压缓冲区有问题?
- 是否客户端输入缓冲区有问题?
实用命令
- 模仿 Redis 压力相干命令
- 常⽤ Redis 内存排查命令
总结
背景
你是否有过这种困扰:我的数据量十分小,但还是报 OOM 谬误?
# ⼀个简略 set 提醒内存不⾜
[root@10-186-61-38 redis]# redis-cli -p 9999 set actionsky 1
(error) OOM command not allowed when used memory > 'maxmemory'.
首先我给大家解释下,Redis 的 OOM 分两种。
- ⼀种是因 Redis 应用内存超出 OS 物理内存,OS 将 Redis 过程杀死。
- 另⼀种是 Redis 应用内存超过
maxmemory
参数配置,引发 Redis Server 层 OOM。
OOM 是 Redis 最常见的内存故障,它影响很大:
- 故障产生时,过程并不会退出,能读但无奈写入。
- 配置了 allkeys-lru、allkeys-lfu 等内存淘汰策略场景下,会有大量键生效,导致缓存命中率急剧下降。
本文中,我会给大家分享下该种内存问题的 排查方向及运维命令。
Redis 内存耗费划分
简短介绍下 Redis 内存耗费划分状况,为下文诊断提供思路。上图能够总结 Redis 耗费内存分如下几块:
- 对象内存:实践上占用最大,存储所有业务数据,如字符串类型、哈希类型对象等。
- 客户端内存:包含输出客户端(查问或写入命令)、输入客户端应用的内存,因为不受 maxmemory 参数管制,这块咱们需重点排查。
- 复制积压缓冲:所有从库客户端共享、保留固定大小的写入命令用于从库失连后数据弥补。
- Redis 本身内存:存储数据元数据信息、过期键字典等。
- AOF 缓冲区:AOF 长久化、重写缓冲区,⼀般占用很少,根本不须要关注。
内存 OOM 会导致哪些问题?
1.Redis 无奈写入,只能读取。
2.Redis 大量键被逐出内存或过期,导致 Redis 查问效率升高(maxmemory-policy 配置为非默认值 noeviction 时)。
排查思路
留神:下文不做特地阐明的话,我的 maxmemory 设置为 1G,其它任何参数为默认。
是否数据量太大?
应用 redis-benchmark 继续灌入数据,
查看内存应用状况,产生 OOM 状态时 used_memory ⼀定会大于 maxmemory。
检查数据对象内存和其它内存应用状况如下图:
这里有必要阐明下 overhead.total,它包含除数据外 Redis 耗费的所有内存,比方后面提到的复制缓冲区、客户端输入输出缓冲区等,另外还包含⼀些元数据如 overhead.hashtable,它是数据库中元数据耗费的内存大小,包含以下三项:
- 整个数据库是⼀种 hash 表,首先就是这张 hash 表应用的内存。
- 每⼀个 key-value 对都有⼀个 dictEntry 来记录他们的关系,元信息便蕴含该 db 中所有 dictEntry 应用的内存。
- redis 应用 redisObject 来形容 value 所对应的不同数据类型(string、list、hash、set、zset),那么 redisObject 占用的空间也计算在元数据。
大家对这个景象可能有点纳闷,为啥我明明设置 maxmemory 为 1G,你 Redis 只给我存了 990 多 M 数据就满了?
很好了解,依据下面测试可知数据达到⼀定规模后,因需耗费额定的元数据、缓存内存,Redis 最终将超过 maxmemory 而 OOM。
是否客户端输出缓冲区有问题?
制作输出缓冲区压力(避免烦扰,先清空数据再压测)
# 要害参数解释
-d 示意每个 set 值的大小,单位为字节
-c 启多少个连贯
压测几秒钟后,触发 OOM,
查看输出缓冲区内存耗费,能看到客户端输出缓冲区耗费总量为 2.4G 左右,远远超过 maxmemory 参数设置。
那我如何找到耗费内存量最大的那个连贯呢?
可通过运行上述查看命令,定位到各客户端输出缓冲区的内存耗费(由大到小排序)。
⼀般如果定位到有连贯异样,能够应用如下命令杀掉。
# 例如杀掉上图中 id=51421 的连贯
127.0.0.1:9999> CLIENT KILL ID 51421
(integer) 1
是否复制积压缓冲区有问题?
为测试不便,我间接把复制积压缓冲区配置为 800M。
开启 redis-benchmark 压测过程,
查看复制积压缓冲区内存耗费,能够看到因为缓冲区设置过大,数据量才存储 190 多 M,Redis 就无奈写入了。
是否客户端输入缓冲区有问题?
若客户端输入缓冲区太大如何排查?⼀般该场景比拟少见,常见于用到了 redis 的 monitor
命令。
留神:monitor 命令性能像 MySQL 的 general-log,能打印 Redis 所有执行的命令。在生产环境极少应用或禁用。
先开启 monitor 命令,
通过 redis-benchmark 制作输入缓冲区压力。
测试⼀段时间后察看 Redis 内存耗费,
此时数据库无奈写入,
查看输入缓冲区各客户端连贯内存耗费、输入缓冲区总耗费内存如下,
能够看到输入缓冲区总内存已远大于 maxmemory
限度,此时内存⾃然就 OMM。
实用命令
上文排查过程有些 Redis 运维命令我认为比拟实用,整顿如下:
模仿 Redis 压力相干命令
# 1. 继续给 Redis 灌数据
redis-benchmark -p 9999 -t set -r 100000000 -l
# 2. 模仿输出缓冲区过大
redis-benchmark -p 9999 -q -c 10 -d 102400000 -n 10000000 -r 50000 -t set
# 3. 模拟输出缓冲区过大
redis-benchmark -p 9999 -t get -r 5000000 -n 10000000 -d 100 -c 1000 -P 500 -l
罕用 Redis 内存排查命令
# 1. 疾速查看 Redis 内存是否够用
redis-cli -p 9999 info memory |egrep
'(used_memory_human|maxmemory_human|maxmemory_policy)'
# 2. 查看复制积压缓冲区应用状况
redis-cli -p 9999 memory stats|egrep -A 1
'(total.allocated|replication.backlog)'
# 3. 查看客户端输出缓冲区内存应用总量
redis-cli -p 9999 client list| awk 'BEGIN{sum=0}
{sum+=substr($12,6);sum+=substr($13,11)}END{print sum}'
# 4. 查看客户端输出缓冲区各客户端连贯的内存状况
redis-cli -p 9999 client list|awk '{print substr($12,6),$1,$12,$18}'|sort -
nrk1,1 | cut -f1 -d" " --complement
# 5. 查看客户端输入缓冲区内存应用总量
redis-cli -p 9999 client list| awk 'BEGIN{sum=0} {sum+=substr($16,6)}END{print
sum}'
# 6. 查看客户端输入缓冲区各客户端连贯的内存应用排序
redis-cli -p 9999 client list|awk '{print substr($16,6),$1,$16,$18}'|sort -
nrk1,1 | cut -f1 -d" " --complement |head -n10
# 7. 检查数据对象应用内存总量
redis-cli -p 9999 memory stats|grep -A 1 'dataset.bytes'
总结
- Redis 内存问题大部分能够通过上述排查思路进行定位。
- 跟大家分享了⼀些罕用 Redis 内存排查命令,心愿对大家有帮忙。
- 如果大家觉命令执行起来不够不便,我整顿了⼀份 Redis 内存查看脚本(篇幅稍长)有趣味能够移步查阅:
https://www.jianshu.com/p/a50…
脚本执行成果: