性能指标
1 Info 命令
redis
使用info
命令获取所有与Redis服务相关的各种信息和统计数值
server 查看 Redis 服务器信息,如 Redis 的版本
clients 客户端的连接部分
memory 内存消耗相关信息 #
persistence RDB和AOF相关信息
stats 一般统计 #
replication 主/从复制信息
cpu 统计CPU的消耗
commandstats Redis命令统计 #
cluster Redis集群信息
keyspace 数据库的相关统计
dbsize: 查看当前db的key数量
1) info memory
只返回与内存相关的数据
指标 | 含义 |
---|---|
used_memory | 由 Redis 分配器分配的内存总量,包含了redis进程内部的开销和数据占用的内存,以字节(byte)为单位,即当前redis使用内存大小。 |
used_memory_human | 已更直观的单位展示分配的内存总量。 |
used_memory_rss | 向操作系统申请的内存大小,与 top 、 ps等命令的输出一致,即redis使用的物理内存大小。 |
used_memory_rss_human | 已更直观的单位展示向操作系统申请的内存大小。 |
used_memory_peak | redis的内存消耗峰值(以字节为单位),即历史使用记录中redis使用内存峰值。 |
used_memory_peak_human | 以更直观的格式返回redis的内存消耗峰值 |
used_memory_peak_perc | 使用内存达到峰值内存的百分比,used_memory/ used_memory_peak) *100%,即当前redis使用内存/历史使用记录中redis使用内存峰值*100% |
used_memory_overhead | Redis为了维护数据集的内部机制所需的内存开销,包括所有客户端输出缓冲区、查询缓冲区、AOF重写缓冲区和主从复制的backlog。 |
used_memory_startup | Redis服务器启动时消耗的内存 |
used_memory_dataset | 数据实际占用的内存大小,即used_memory-used_memory_overhead |
used_memory_dataset_perc | 数据占用的内存大小的百分比,100%*(used_memory_dataset/(used_memory-used_memory_startup)) |
total_system_memory | 整个系统内存 |
total_system_memory_human | 以更直观的格式显示整个系统内存 |
used_memory_lua | Lua脚本存储占用的内存 |
used_memory_lua_human | 以更直观的格式显示Lua脚本存储占用的内存 |
maxmemory | Redis实例的最大内存配置 |
maxmemory_human | 以更直观的格式显示Redis实例的最大内存配置 |
maxmemory_policy | 当达到maxmemory时的淘汰策略 |
mem_fragmentation_ratio | 碎片率,used_memory_rss/ used_memory。ratio指数>1表明有内存碎片,越大表明越多,<1表明正在使用虚拟内存,虚拟内存其实就是硬盘,性能比内存低得多,这是应该增强机器的内存以提高性能。一般来说,mem_fragmentation_ratio的数值在1 ~ 1.5之间是比较健康的。详解 |
mem_allocator | 内存分配器 |
active_defrag_running | 表示没有活动的defrag任务正在运行,1表示有活动的defrag任务正在运行(defrag:表示内存碎片整理)详解 |
lazyfree_pending_objects | 0表示不存在延迟释放的挂起对象 |
2) info stats
一般统计信息
指标 | 含义 |
---|---|
total_connections_received | 服务器接受的连接总数 |
total_commands_processed | 服务器处理的命令总数 |
instantaneous_ops_per_sec | 每秒处理的命令数 |
rejected_connections | 由于maxclients限制而拒绝的连接数 |
expired_keys | key到期事件的总数 |
evicted_keys | 由于maxmemory最大内存限制而导致被驱逐的key的数量 |
keyspace_hits | key命中次数 |
keyspace_misses | key未命中次数 |
3) info clients
已连接客户端信息
指标 | 含义 |
---|---|
connected_clients | 已连接客户端的数量(不包括通过从属服务器连接的客户端 |
client_longest_output_list | 当前连接的客户端当中,最长的输出列表 |
client_biggest_input_buf | 当前连接的客户端当中,最大输入缓存 |
blocked_clients | 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量 |
4) info cpu
统计CPU的消耗
指标 | 含义 |
---|---|
used_cpu_sys | 消耗的系统CPU |
used_cpu_user | 消耗的用户CPU |
used_cpu_sys_children | 后台进程占用的系统CPU |
used_cpu_user_children | 后台进程占用的用户CPU |
5) info commandstats
Redis命令统计
提供基于命令类型的统计信息,包括调用次数,这些命令消耗的总CPU时间以及每个命令执行消耗的平均CPU时间
对于每一个命令类型,添加以下行:
cmdstat_XXX: calls=XXX,usec=XXX,usec_per_call=XXX
calls 次数
usec 时间
usec_per_call 平均时间
2 memory 命令
获得有关服务器内存的其他内省信息,可以参考MEMORY STATS
和MEMORY DOCTOR
指标 | 含义 |
---|---|
MEMORY DOCTOR | 列出 Redis 服务器遇到的内存相关问题,并提供相应的解决建议 |
MEMORY MALLOC-STATS | 提供内存分配情况的内部统计报 |
MEMORY PURGE | 尝试清除脏页以便内存分配器回收使用 |
MEMORY USAGE key | 给出一个 key 和它的值在 RAM 中所占用的字节数 |
MEMORY STATS |
将服务器的内存使用情况以数组情况返回 |
jemalloc作为内存分配器
1) MEMORY STATS
命令将服务器的内存使用情况以数组情况返回
指标 | 含义 |
---|---|
peak.allocated | redis启动以来,allocator分配的内存峰值,单位字节;同INFO的used_memory_peak |
total.allocated | allocator 当前分配的内存总字节数;同 INFO命令used_memeory |
startup.allocated | Redis启动完成消耗的内存字节数;同INFO的used_memory_startup |
clients.normal | Redis所有常规客户端内存消耗总字节数(查询输出缓冲区,连接内存消耗) |
overhead.total | Redis 额外内存消耗总字节数,i.e. startup.allocated, replication.backlog, clients.slaves, clients.normal, aof.buffer 以及管理keyspace使用的内部数据接口消耗的内存字节数 同INFO的used_memory_overhead |
keys.count | 整个redis实例key的个数 |
keys.bytes-per-key | 每个key平均字节数,net memory usage(total.allocated 减去 startup.allocated)与keys.count的比值 |
dataset.bytes | Redis 实例中数据占用的总字节数,计算方法total.allocated减去overhead.total |
dataset.percentage | Redis 数据消耗内存占总内存的百分比 |
peak.percentage | 当前内存消耗占峰值内存消耗的百分比 |
参考 » Redis 为什么变慢了?一文讲透如何排查 Redis 性能问题 | 万字长文
redis性能排查调优
1) 确定Redis链路耗时变长
- (1)业务服务器到 Redis 服务器之间的网络存在问题,例如网络线路质量不佳,网络数据包在传输时存在延迟、丢包等情况 ( 第一种情况发生的概率比较小,如果是服务器之间网络存在问题,那部署在这台业务服务器上的所有服务都会发生网络延迟的情况,此时你需要联系网络运维同事,让其协助解决网络问题 )
- (2)Redis 本身存在问题,需要进一步排查是什么原因导致 Redis 变慢
首先对 Redis 进行基准性能测试
,了解Redis 在生产环境服务器上的基准性能
基准性能
就是指 Redis 在一台负载正常的机器上
最大的响应延迟
平均响应延迟
避免业务服务器到 Redis 服务器之间的网络延迟,你需要直接在 Redis 服务器上测试实例的响应延迟情况
# 60 秒内的最大响应延迟
redis-cli -h 10.0.0.207 -p 16379 --intrinsic-latency 60
...
Max latency so far: 1488 microseconds.
Max latency so far: 5059 microseconds.
# 每间隔 1 秒,采样 Redis 的平均操作耗时
redis-cli -h 10.0.0.207 -p 16379 --latency-history -i 1
min: 0, max: 7, avg: 0.43 (95 samples) -- 1.00 seconds range
...
2) 慢查询定位 slowlog
127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 32693 # 慢日志ID
2) (integer) 1593763337 # 执行时间戳
3) (integer) 5299 # 执行耗时(微秒)
4) 1) "LPUSH" # 具体执行的命令和参数
2) "Ftask"
3) "0"
3) 避免使用复杂度过高的命令
-
尽量不使用 O(N) 以上复杂度过高的命令,对于
数据的聚合操作 (例如 SORT、SUNION、ZUNIONSTORE )
,放在客户端做 -
执行 O(N) 命令,保证
N 尽量的小(推荐 N <= 300)
,每次获取尽量少的数据,让 Redis 可以及时处理返回
4) 避免操作 bigkey
慢日志发现 SET / DEL
这种简单命令出现在慢日志中,那么你就要怀疑你的实例否写入了 bigkey
# 扫描 bigkey 的分布
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01 (单位是秒)
Sampled 103 keys in the keyspace!
Total key length in bytes is 4299 (avg len 41.74)
Biggest string found 'stats:crawler:200:lifetime' has 12304 bytes
Biggest list found 'mplete:items' has 2128537 items
Biggest set found 'link:blacklist' has 3 members
Biggest zset found 'stats:200:86400' has 148509 members
45 strings with 14416 bytes (43.69% of keys, avg size 320.36)
3 lists with 2135188 items (02.91% of keys, avg size 711729.33)
3 sets with 5 members (02.91% of keys, avg size 1.67)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
52 zsets with 355218 members (50.49% of keys, avg size 6831.12)
原理: Redis 在内部执行了 SCAN 命令,遍历整个实例中所有的 key,然后针对 key 的类型,分别执行 STRLEN、LLEN、HLEN、SCARD、ZCARD 命令,来获取 String 类型的长度、容器类型(List、Hash、Set、ZSet)的元素个数
注意: 对线上实例进行 bigkey 扫描时,Redis 的 OPS 会突增,为了降低扫描过程中对 Redis 的影响,最好控制一下扫描的频率,指定 -i 参数即可
优化:
1) 业务应用尽量避免写入 bigkey
2) Redis 4.0+,用 UNLINK 命令替代 DEL
此命令可以把释放 key 内存的操作,放到后台线程中去执行,从而降低对 Redis 的影响
3) 开启 lazy-free, 执行 DEL 命令时,释放内存也会放到后台线程中执行
5) 避免过期时间集中
Redis 的过期数据采用被动过期
+ 主动过期
两种策略
被动过期:只有当访问某个 key 时,才判断这个 key 是否已过期,如果已过期,则从实例中删除
主动过期:Redis 内部维护了一个定时任务,默认每隔 100 毫秒(1 秒 10 次)就会从全局的过期哈希表中随机取出 20 个 key,然后删除其中过期的 key,如果过期 key 的比例超过了 25%,则继续重复此过程,直到过期 key 的比例下降到 25% 以下,或者这次任务的执行耗时超过了 25 毫秒,才会退出循环
主动过期 key 的定时任务,是在 Redis 主线程中执行
优化:
1) 集中过期 key 增加一个随机过期时间,把集中过期的时间打散,降低 Redis 清理过期 key 的压力
2) Redis 4.0 +,可以开启 lazy-free 机制,当删除过期 key 时,把释放内存的操作放到后台线程中执行,避免阻塞主线程
6) 实例内存达到上限maxmemory
当 Redis 内存达到 maxmemory
后,每次写入新的数据之前,Redis 必须先从实例中踢出一部分数据,让整个实例的内存维持在 maxmemory
之下,然后才能把新数据写进来
踢出旧数据的逻辑也是需要消耗时间的,而具体耗时的长短,要取决于你配置的淘汰策略:
allkeys-lru:不管 key 是否设置了过期,淘汰最近最少访问的 key
volatile-lru:只淘汰最近最少访问、并设置了过期时间的 key
allkeys-random:不管 key 是否设置了过期,随机淘汰 key
volatile-random:只随机淘汰设置了过期时间的 key
allkeys-ttl:不管 key 是否设置了过期,淘汰即将过期的 key
noeviction:不淘汰任何 key,实例内存达到 maxmeory 后,再写入新数据直接返回错误
allkeys-lfu:不管 key 是否设置了过期,淘汰访问频率最低的 key(4.0+版本支持)
volatile-lfu:只淘汰访问频率最低、并设置了过期时间 key(4.0+版本支持)
一般最常使用的是 allkeys-lru / volatile-lru
淘汰策略
如果此时你的 Redis 实例中还存储了 bigkey,那么在淘汰删除 bigkey 释放内存时,也会耗时比较久
优化:
1) 避免存储 bigkey,降低释放内存的耗时
2) 淘汰策略改为随机淘汰,随机淘汰比 LRU 要快很多(视业务情况调整)
3) 拆分实例,把淘汰 key 的压力分摊到多个实例上
4) Redis 4.0 +,开启 layz-free 机制,把淘汰 key 释放内存的操作放到后台线程中执行(配置 lazyfree-lazy-eviction = yes)
7) 数据持久化 fork 耗时严重
info stats
latest_fork_usec:19408 (微秒)
这个时间就是主进程在 fork 子进程期间,整个实例阻塞无法处理客户端请求的时间
果你发现这个耗时很久,就要警惕起来了,这意味在这期间,你的整个 Redis 实例都处于不可用的状态。
优化:
1)控制 Redis 实例的内存:尽量在 10G 以下,执行 fork 的耗时与实例大小有关,实例越大,耗时越久
2) 合理配置数据持久化策略:在 slave 节点执行 RDB 备份,推荐在低峰期执行,而对于丢失数据不敏感的业务(例如把 Redis 当做纯缓存使用),可以关闭 AOF 和 AOF rewrite
3)Redis 实例不要部署在虚拟机上:fork 的耗时也与系统也有关,虚拟机比物理机耗时更久
4)降低主从库全量同步的概率:适当调大 repl-backlog-size 参数,避免主从全量同步
8)关闭 内存大页
主进程在拷贝内存数据时,这个阶段就涉及到新内存的申请,如果此时操作系统开启了内存大页,那么在此期间,客户端即便只修改 10B 的数据,Redis 在申请内存时也会以 2MB 为单位向操作系统申请,申请内存的耗时变长,进而导致每个写请求的延迟增加,影响到 Redis 性能
cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
输出选项是 always,就表示目前开启了内存大页机制,我们需要关掉它
echo never > /sys/kernel/mm/transparent_hugepage/enabled
开启内存大页,可以在一定程序上降低应用程序申请内存的次数
但是对于 Redis 这种对性能和延迟极其敏感的数据库来说,我们希望 Redis 在每次申请内存时,耗时尽量短,
不建议你在 Redis 机器上开启这个机制
汇总
CPU 相关:使用复杂度过高命令、数据的持久化,都与耗费过多的 CPU 资源有关
内存相关:bigkey 内存的申请和释放、数据过期、数据淘汰、碎片整理、内存大页、内存写时复制都与内存息息相关
磁盘相关:数据持久化、AOF 刷盘策略,也会受到磁盘的影响
网络相关:短连接、实例流量过载、网络流量过载,也会降低 Redis 性能
计算机系统:CPU 结构、内存分配,都属于最基础的计算机系统知识
操作系统:写时复制、内存大页、Swap、CPU 绑定,都属于操作系统层面的知识