redis内存淘汰
https://redis.io/docs/latest/develop/reference/eviction/
在 Redis 中,使用 allkeys-lru 策略时,并不是一次删除一个特定的键,而是通过内存使用情况以及 LRU 算法来选择一批最久未使用的键进行删除。当 Redis 内存达到最大限制(maxmemory)时,它会触发淘汰过程。此时,Redis 会根据设置的 maxmemory-policy(比如 allkeys-lru)删除一些键,以便腾出内存。
删除的比例和删除过程
-
淘汰过程 Redis 的 LRU(Least Recently Used)算法会在内存达到
maxmemory限制时,开始删除最久未使用的键。此过程不是一次性删除特定比例的键,而是通过计算最久未访问的键来逐渐删除,直到内存使用量降到合理范围。 -
删除比例 由于 Redis 是基于 LRU 算法进行内存淘汰的,并不会设置一个固定的删除比例,而是根据实际情况删除键。具体删除多少个键是由 Redis 内存使用量、剩余空间以及键的访问频率决定的。通常 Redis 会删除那些长时间没有被访问的键,但删除的数量并不是固定的比例。
-
LRU 删除的键数 Redis 通过对所有键的 LRU 时间戳进行排序(根据最近的访问时间),从而决定哪些键最久未被使用。然后它会将这些键删除。这个删除过程会持续进行,直到释放足够的内存。
代码层面
在 Redis 中,关于 allkeys-lru 策略的内存淘汰代码主要体现在 src/server.c 中,特别是在 evictKey 和相关的淘汰函数里。以下是与 LRU 淘汰相关的代码流程:
-
判断是否达到最大内存
当 Redis 的内存使用量超过
maxmemory限制时,Redis 会开始执行内存淘汰过程。if (used_memory > server.maxmemory) { // 执行淘汰操作 eviction = evict_lru(); } -
LRU 淘汰逻辑
Redis 会遍历键,选择最久未访问的键进行淘汰。具体的淘汰操作通过
lru_eviction()函数进行,这个函数会根据 LRU 策略选择键进行删除。// LRU 淘汰算法 eviction = lru_eviction(); -
LRU 删除的数量
Redis 内部并没有明确限制一次删除多少个键,而是通过内存使用情况决定删除的键数。一次可能删除一个键,也可能删除多个键,具体取决于剩余内存的大小和需要释放的空间。
// 内存释放 while (used_memory > server.maxmemory) { // 选择最久未使用的键进行删除 evict_lru_key(); }
如何控制删除的频率
虽然 Redis 本身没有提供直接控制删除比例的配置项,但你可以通过以下方式间接影响内存的删除频率:
-
增加
maxmemory设置如果
maxmemory设置得更高,Redis 会在内存达到限制之前有更大的空间,这样可以减少删除的频率。 -
调整
maxmemory-policy根据你的应用需求,选择合适的内存淘汰策略,例如:
-
allkeys-lru:会根据 LRU 策略淘汰最久未使用的键。 -
allkeys-lfu:会根据 LFU 策略淘汰访问频率最低的键。
-
-
使用
maxmemory-samplesRedis 使用
maxmemory-samples参数来决定每次内存淘汰时扫描的样本数。增加maxmemory-samples的值会使 Redis 更精确地选择需要淘汰的键,但也会导致更多的计算开销。maxmemory-samples 10这个值决定了 Redis 每次扫描多少个样本进行内存淘汰,增大它会增加删除精度,但也会增加 Redis 的计算负担。
总结
-
删除的比例:Redis 的 LRU 和 LFU 淘汰策略并没有固定的删除比例。它会根据内存使用情况和键的访问历史来选择最适合删除的键。删除的数量会动态变化,直到释放足够的内存。
-
如何影响删除过程:可以通过调整
maxmemory、maxmemory-policy和maxmemory-samples参数来间接影响删除频率和精度,但不能直接设置固定的删除比例。
在 Redis 中,maxmemory-samples 是一个用来控制在内存淘汰过程中每次随机选择样本的数量的配置项。它的目的是在执行内存淘汰时,让 Redis 更加准确地选择最合适的键进行删除,尤其是在使用 allkeys-lru 或 allkeys-lfu 这类策略时。
maxmemory-samples 的作用
-
该参数指定了 Redis 在进行内存淘汰时,从所有键中随机抽取的样本数目。Redis 通过这些样本来估算哪些键最适合被淘汰。
-
默认情况下,
maxmemory-samples的值为 5,表示每次从 Redis 的键中随机选择 5 个样本来进行评估。 -
如果你将该值设置为较大的数值(如 10000),Redis 每次会随机抽取更多的样本来进行评估。这将使得内存淘汰的选择更准确,但也会带来更多的计算开销。
设置 maxmemory-samples 为 10000 的影响
-
提高淘汰准确性
-
设置
maxmemory-samples为较大的值(如 10000),可以提高 Redis 在淘汰过程中对于哪些键需要被删除的判断精度。这意味着 Redis 会更准确地评估哪些键是最久未使用或最少被访问的,从而减少错误淘汰的风险。
-
-
增加计算开销
-
每次进行内存淘汰时,Redis 需要检查更多的样本(例如 10000 个样本),这将增加内存消耗和 CPU 开销。如果你设置的样本数过大,可能会导致 Redis 在高负载时性能下降。
-
-
适用场景
-
如果你的 Redis 数据集很大,且内存淘汰策略对性能要求较高,增加样本数可以改善内存管理的效果。但需要注意的是,设置过大的值可能会导致 CPU 使用率过高,尤其是在高并发的情况下。
-
设置为 10000 是否合适?
-
小型和中型 Redis 实例:如果你的 Redis 实例的内存和 CPU 资源比较充足,且数据量不是非常庞大,设置
maxmemory-samples为 10000 是可以的。但你需要监控性能开销。 -
大型 Redis 实例:如果你的 Redis 实例数据非常大且 CPU 和内存资源有限,设置为 10000 可能会导致性能瓶颈。可以考虑根据实际负载和性能需求逐步增加该值,而不是一次性设为 10000。
如何修改 maxmemory-samples
可以通过修改 Redis 配置文件(redis.conf)或动态修改该配置项:
配置文件中修改:
maxmemory-samples 10000
动态修改:
使用 Redis 命令 CONFIG SET 来动态修改 maxmemory-samples 的值:
CONFIG SET maxmemory-samples 10000
验证效果
要验证设置 maxmemory-samples 为 10000 是否有效,可以通过以下几步来监控和分析 Redis 的性能:
-
监控 CPU 使用情况:可以使用
top或htop等工具监控 Redis 进程的 CPU 使用情况。如果你设置了较高的maxmemory-samples,并且 Redis 在淘汰时的 CPU 使用率过高,可能说明设置过高。 -
查看淘汰日志:使用
redis-cli或MONITOR命令来观察 Redis 是否频繁地进行内存淘汰操作。你可以通过设置maxmemory-policy来测试不同淘汰策略对内存使用的影响。 -
分析响应时间:通过
redis-benchmark或自定义负载测试,验证 Redis 的响应时间是否因为高样本数的设置而变得较慢。
总结
-
设置
maxmemory-samples为 10000 可以提高内存淘汰策略的精度,但也会增加 Redis 的计算开销,特别是在高负载环境下。 -
在决定是否设置该值时,需要平衡精度和性能,避免设置过高导致 Redis 性能问题。
-
通过逐步调整和监控性能,找到最适合自己场景的配置。
Redis 淘汰策略源码分析
-
allkeys-lru和allkeys-lfu淘汰策略源码 Redis 的内存淘汰策略在src/server.c中有相关代码实现。在选择淘汰策略时,Redis 通过检查配置中的maxmemory-policy值来决定使用哪种策略。-
allkeys-lru:使用 LRU(Least Recently Used)算法,删除最久未访问的键。 -
allkeys-lfu:使用 LFU(Least Frequently Used)算法,删除访问频率最低的键。
以下是
src/server.c中与内存淘汰相关的部分代码(伪代码表示):// 选择删除策略的函数 if (server.maxmemory_policy == MAXMEMORY_VOLATILE_LRU) { // 使用 LRU 策略删除最久未使用的键 eviction = lru_eviction(); } else if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LRU) { // 使用 LRU 策略删除最久未使用的键 eviction = allkeys_lru_eviction(); } else if (server.maxmemory_policy == MAXMEMORY_ALLKEYS_LFU) { // 使用 LFU 策略删除访问频率最低的键 eviction = allkeys_lfu_eviction(); }eviction函数会在 Redis 内存达到最大限制时被调用,选择最合适的键进行淘汰。 -
-
notify-keyspace-events配置说明notify-keyspace-events是 Redis 的一个配置选项,用于指定 Redis 在键空间中发生某些事件时触发的通知。该配置允许你订阅不同类型的事件,并在事件发生时获得通知。这个选项对内存淘汰策略没有直接影响,但它会影响 Redis 的行为,特别是对于某些需要监控键操作(如过期、删除等)的场景。Redis 事件通知的类型分为两类:
-
事件类型(Event Types):包括键过期(
E)、键删除(d)、键修改(m)等。 -
事件内容(Keyspace Events):针对具体键空间中的变化(例如过期、删除等)。
配置方法: 你可以在 Redis 配置文件中启用键空间通知,例如:
notify-keyspace-events Ex-
E:代表过期事件(expire)。 -
x:代表删除事件(del)。
通过这种配置,你可以让 Redis 在键过期或被删除时,向订阅者发送通知。这对于一些应用场景非常有用,例如:
-
监控缓存失效。
-
分布式锁的过期通知。
-
实现一些更复杂的应用逻辑(如事件驱动模型)。
-
是否有必要配置 notify-keyspace-events
是否需要配置 notify-keyspace-events 取决于你的应用需求,具体说明如下:
为什么要配置 notify-keyspace-events
-
监控过期事件和删除事件:如果你的应用需要在键过期或被删除时执行特定的操作(例如更新某个状态或触发某个动作),启用此功能会非常有用。
-
用于缓存系统:在缓存系统中,键的过期和删除是常见的操作。如果你想通过通知机制来实时获取哪些键被删除或过期,这个配置非常重要。例如,你可以在某些缓存失效时自动刷新数据。
-
分布式锁:在分布式缓存中,
notify-keyspace-events配置可以帮助你监控分布式锁的过期,确保锁过期后自动释放。 -
应用级别的事件驱动模型:如果你的应用依赖于 Redis 键的变化来触发某些事件(如过期、删除、修改),启用通知机制将有助于实现更精确的事件驱动模型。
什么时候不需要配置
-
没有特殊监控需求:如果你的应用不依赖于键空间的变化,或者只是依赖 Redis 的普通功能(如存储、获取键),那么没有必要启用此配置。
-
性能考虑:启用键空间通知会带来额外的性能开销。虽然 Redis 在处理通知时不会阻塞客户端,但对于高频的键变化(如大量的过期和删除事件),可能会影响 Redis 性能。
配置和验证示例
假设你需要在键过期或删除时执行某个操作,可以通过以下方式进行配置和验证:
-
修改 Redis 配置文件(
redis.conf):在
redis.conf文件中添加或修改:notify-keyspace-events Ex这将启用对过期事件(
E)和删除事件(x)的通知。 -
使用
PSUBSCRIBE订阅事件:你可以使用
PSUBSCRIBE命令订阅键空间事件。以下是一个订阅过期和删除事件的示例:PSUBSCRIBE __keyevent@0__:expired PSUBSCRIBE __keyevent@0__:del这将订阅键空间中所有数据库(假设使用默认的数据库 0)的过期和删除事件。
-
验证事件通知:
-
通过 Redis CLI 手动删除或过期某个键。
-
观察是否收到事件通知(
__keyevent@0__:expired或__keyevent@0__:del)。
-
总结
-
maxmemory-policy是决定 Redis 内存淘汰策略的配置项,与notify-keyspace-events配置无直接关系。 -
notify-keyspace-events配置对 Redis 的键空间事件通知非常有用,尤其是在需要对键的过期、删除等事件做出反应的场景中。 -
是否启用
notify-keyspace-events需要根据你的应用需求来决定,开启后可能对性能有一些影响,特别是高频变化的场景。
确实,Redis 并不会直接在 INFO stats 输出中显示 lfu_counter 和 lfu_total_hits,这些字段仅在一些特殊的 Redis 版本中(比如,特定配置的 Redis 或专门的模块)才可能出现。对于默认的 Redis 实例,尤其是启用了 LFU 淘汰策略的实例,LFU 计数器的内部状态并不会直接暴露。
不过,你依然可以通过以下几种方法间接获取有关 LRU 和 LFU 的信息:
1. 通过 INFO 命令查看 LFU 相关统计数据(间接方法)
在 Redis 4.0 及以上版本中,LFU 相关的数据会在 INFO memory 输出中显示。例如:
INFO memory
此时,会返回关于内存使用的相关统计信息,其中可能包含以下部分:
-
lfu_algorithm: 显示当前使用的 LFU 算法(比如,LRU-LFU)。 -
evicted_keys: 被驱逐的键数。
这些信息并不直接提供单个键的 LFU 计数器,但它们帮助你了解 LFU 算法的整体行为。
2. 监控 LFU 使用情况:
虽然 Redis 没有直接的命令列出 LFU 计数器,但你可以通过 Keyspace Notifications 来监控某些操作,间接推测哪些键可能是低频访问的。例如,监听 expired 事件,了解何时某个键过期,间接推测该键是否因为低频访问被淘汰。
CONFIG SET notify-keyspace-events Ex
然后,你可以订阅这些事件:
PSUBSCRIBE __keyevent@0__:expired
这将监听键过期事件,可以帮助你了解哪些键被淘汰。
3. 通过 SCAN 命令遍历所有键并查看 TTL(间接查看)
通过 SCAN 命令遍历所有键,并查看它们的 TTL 值,帮助你间接了解哪些键是“最久未访问”的(即没有 TTL 设置或者过期时间很长)。例如:
SCAN 0 MATCH * COUNT 1000
这个命令将遍历 Redis 中的键,并逐个返回。然后,你可以检查键的 TTL:
TTL <key_name>
如果某个键的 TTL 很长,可能表示该键在一段时间内没有被访问。
4. 自定义脚本或监控工具
你也可以写脚本周期性地扫描 Redis 中的键并记录它们的访问时间或 TTL。可以通过这个脚本推断哪些键是“最久未访问”的(低频访问的键)。例如,使用 Python 或其他 Redis 客户端工具,定期检查并统计键的 TTL。
5. 使用 Redis 调试模式
如果你只是想在特定情况下深入查看键的 LRU 或 LFU 状态,可以使用 Redis 的调试命令来跟踪一些操作:
DEBUG OBJECT <key_name>
这个命令会返回关于该键的一些内部状态信息,包括 LRU 时间戳等。
总结
Redis 本身并没有直接提供完整的 lfu_counter 或 lru_counter 统计信息,无法直接查看每个键的访问频率。你可以通过以下方式来间接了解 LFU 或 LRU 相关的信息:
-
使用
INFO memory查看一些内存统计信息。 -
利用 Keyspace Notifications 监听过期事件。
-
使用
SCAN命令和TTL来间接推测键的访问频率。 -
自定义脚本和监控工具来追踪访问时间。
这些方法可以帮助你了解哪些键可能是最久未访问或最低频访问的。
下面是 Redis INFO 命令所有模块和字段的完整解释(适用于 Redis 6.x/7.x,支持集群/主从/持久化等场景)。为便于理解,分模块系统讲解:
🔹 1. Server(服务器信息)
| 字段 | 含义 |
|---|---|
| redis_version | Redis 版本 |
| redis_git_sha1 | 构建时 Git 哈希(开发版) |
| redis_git_dirty | 是否包含未提交更改 |
| redis_build_id | Redis 编译时生成的 ID |
| redis_mode | 运行模式(standalone/cluster/sentinel) |
| os | 操作系统信息 |
| arch_bits | CPU 架构位数(32/64) |
| multiplexing_api | 网络多路复用库(如 epoll/kqueue) |
| process_id | Redis 进程 PID |
| run_id | 唯一标识符(可用于 Sentinel) |
| tcp_port | TCP 监听端口 |
| uptime_in_seconds | Redis 已运行时间(秒) |
| uptime_in_days | Redis 已运行时间(天) |
| hz | Redis 主循环频率 |
| configured_hz | 配置的 HZ |
| lru_clock | LRU 时间戳(用于淘汰策略) |
| executable | Redis 执行文件路径 |
| config_file | 启动时使用的配置文件路径 |
🔹 2. Clients(客户端连接信息)
| 字段 | 含义 |
|---|---|
| connected_clients | 当前连接的客户端总数(不包括自身) |
| cluster_connections | cluster 模式下 node-to-node 的连接数量 |
| max_input_buffer | 所有客户端中最大输入缓冲区 |
| max_output_buffer | 所有客户端中最大输出缓冲区 |
| client_recent_max_input_buffer | 最近最大输入缓冲区大小 |
| client_recent_max_output_buffer | 最近最大输出缓冲区大小 |
| blocked_clients | 正在阻塞的客户端数量(如 BLPOP) |
🔹 3. Memory(内存使用)
| 字段 | 含义 |
|---|---|
| used_memory | Redis 当前已分配的总内存 |
| used_memory_human | 可读格式的内存 |
| used_memory_rss | 实际占用的物理内存(包括碎片) |
| used_memory_peak | 内存使用峰值 |
| used_memory_peak_human | 可读格式峰值 |
| used_memory_dataset | 存储数据的实际内存(剔除内部结构) |
| used_memory_dataset_perc | 占总内存的百分比 |
| allocator_allocated | 分配器分配的内存 |
| allocator_active | 活跃内存(分配但未释放) |
| allocator_resident | 驻留内存(映射到物理页) |
| total_system_memory | 系统总内存 |
| used_memory_lua | Lua 脚本使用的内存 |
| used_memory_scripts | 所有缓存脚本内存占用 |
| number_of_cached_scripts | 缓存的 Lua 脚本数量 |
| maxmemory | 配置的最大内存上限(0 表示无限) |
| maxmemory_policy | 淘汰策略(如 noeviction, allkeys-lru) |
| mem_fragmentation_ratio | 内存碎片比(rss/used_memory) |
| mem_fragmentation_bytes | 实际碎片字节数 |
| active_defrag_running | 是否正在执行主动碎片整理(0/1) |
| lazyfree_pending_objects | 延迟删除的对象数量 |
🔹 4. Persistence(持久化)
| 字段 | 含义 |
|---|---|
| loading | 是否正在载入 RDB 文件 |
| rdb_changes_since_last_save | 距上次保存后变更的 key 数 |
| rdb_bgsave_in_progress | 是否正在后台保存 RDB |
| rdb_last_save_time | 上次成功保存时间(Unix 时间戳) |
| rdb_last_bgsave_status | 上次保存结果(ok/fail) |
| rdb_last_bgsave_time_sec | 上次保存耗时(秒) |
| rdb_current_bgsave_time_sec | 当前保存耗时(秒) |
| aof_enabled | 是否启用了 AOF |
| aof_rewrite_in_progress | 是否正在重写 AOF |
| aof_rewrite_scheduled | 是否等待 AOF 重写 |
| aof_last_rewrite_time_sec | 上次 AOF 重写耗时(秒) |
| aof_current_rewrite_time_sec | 当前 AOF 重写耗时(秒) |
| aof_last_bgrewrite_status | 上次重写状态 |
| aof_last_write_status | 最近一次写入状态 |
| aof_current_size | 当前 AOF 文件大小 |
| aof_base_size | 上次重写后 AOF 大小 |
| aof_pending_rewrite | 是否挂起重写 |
| aof_buffer_length | 当前 AOF 缓冲区长度 |
| aof_rewrite_buffer_length | AOF 重写缓冲区大小 |
| aof_pending_bio_fsync | bio fsync 任务队列长度 |
| aof_delayed_fsync | AOF 写入延迟次数 |
🔹 5. Stats(统计信息)
| 字段 | 含义 |
|---|---|
| total_connections_received | 运行以来连接总数 |
| total_commands_processed | 运行以来处理命令总数 |
| instantaneous_ops_per_sec | 当前每秒执行的命令数 |
| total_net_input_bytes | 网络输入总字节数 |
| total_net_output_bytes | 网络输出总字节数 |
| instantaneous_input_kbps | 当前输入速度(KB/s) |
| instantaneous_output_kbps | 当前输出速度(KB/s) |
| rejected_connections | 被拒绝的连接数(连接过多) |
| sync_full | 完整复制次数(PSYNC失败) |
| sync_partial_ok | 增量复制成功次数 |
| sync_partial_err | 增量复制失败次数 |
| expired_keys | 过期 key 数量 |
| evicted_keys | 被淘汰 key 数量 |
| keyspace_hits | key 查询命中次数 |
| keyspace_misses | key 查询未命中次数 |
| pubsub_channels | 正在使用的频道数 |
| pubsub_patterns | 模式匹配的订阅数 |
| latest_fork_usec | 上次 fork 用时(微秒) |
| migrate_cached_sockets | MIGRATE 命令缓存 socket 数 |
| slave_expires_tracked_keys | 从节点正在跟踪的过期 key 数 |
| active_defrag_hits/misses | 主动 defrag 的命中/未命中统计 |
| active_defrag_key_hits/misses | 主动 defrag 命中/未命中 key 数 |
🔹 6. Replication(复制)
| 字段 | 含义 |
|---|---|
| role | 当前角色(master/slave) |
| connected_slaves | 连接的从节点数量 |
| slave0... | 每个从节点状态(IP、port、offset、延迟) |
| master_replid / replid2 | 主节点 ID(用于 PSYNC) |
| master_repl_offset | 当前复制偏移量 |
| second_repl_offset | 上次主 ID 的复制偏移量 |
| repl_backlog_active | 是否启用复制 backlog |
| repl_backlog_size | backlog 大小 |
| repl_backlog_first_byte_offset | backlog 的第一个字节 offset |
| repl_backlog_histlen | backlog 的历史长度(数据实际长度) |
🔹 7. CPU(CPU 使用情况)
| 字段 | 含义 |
|---|---|
| used_cpu_sys | Redis 主线程内核态耗时(秒) |
| used_cpu_user | Redis 主线程用户态耗时(秒) |
| used_cpu_sys_children | Redis 子进程内核态耗时(RDB/AOF) |
| used_cpu_user_children | Redis 子进程用户态耗时 |
🔹 8. Cluster(集群状态)
| 字段 | 含义 |
|---|---|
| cluster_enabled | 是否启用集群模式(1/0) |
🔹 9. Keyspace(数据库信息)
| 字段 | 含义 |
|---|---|
| db0:keys=xxx,expires=xxx,avg_ttl=xxx | 当前库(db0)中 key 数量、带过期的 key 数、平均 TTL(毫秒) |
🔹(可选)Module(模块信息,如 RedisBloom、RedisSearch)
当你加载模块时会显示,例如:
module:name=ReJSON,ver=20000,...
🔹(可选)Keyspace-events / Stream / TLS 等段落
根据启用的功能,INFO 输出可能包含:
-
Stream 指标(消费者组、等待项)
-
TLS 连接统计(TLS 客户端、失败次数)
-
Keyspace events 指标
✅ 小结
| 模块 | 用途 |
|---|---|
| Server | 基本元信息 |
| Clients | 客户端连接与缓存情况 |
| Memory | 内存用量与碎片 |
| Persistence | 持久化状态 |
| Stats | 命令和性能统计 |
| Replication | 主从状态 |
| CPU | 资源消耗分析 |
| Cluster | 是否启用集群 |
| Keyspace | 各 DB 中的 key 情况 |
如你有:
-
特定模块需要重点讲解
-
想把这些信息转成结构化表格、JSON 或导出
-
用
INFO做自动化监控脚本(如 Python、Shell)
可以告诉我,我可继续为你定制。
下面在你已了解的 Redis INFO 命令输出字段的基础上,补充性能分析相关指标,包括:
-
✅ 哪些字段与性能强相关
-
✅ 如何解读性能瓶颈
-
✅ 常用的性能分析组合
-
✅ 对于高负载场景的重点监控建议
🧠 一、核心性能分析指标分类汇总
| 类别 | 字段 | 说明 | 高值可能意味着 |
|---|---|---|---|
| 命令执行速率 | instantaneous_ops_per_sec |
每秒处理命令数 | 命令繁重或压力高 |
| 网络带宽 | instantaneous_input_kbps, instantaneous_output_kbps |
每秒网络 I/O 量(KB) | 客户端流量大 |
| 查询效率 | keyspace_hits, keyspace_misses |
key 查询命中/未命中数 | 命中率低 → 内部结构设计不合理 |
| key 命中率 | (hits / (hits + misses)) |
Redis 缓存命中率 | 命中率低说明缓存失效频繁 |
| 慢查询计数 | slowlog (外部命令) |
记录执行时间超过阈值的命令 | 命令设计或数据结构存在问题 |
| fork 性能 | latest_fork_usec |
上次 fork() 耗时(μs) |
若频繁 fork 且时间 >1s,性能下降 |
| 内存淘汰频率 | evicted_keys |
淘汰的 key 数量 | 超出 maxmemory 且策略触发 |
| 延迟指标 | Redis 需单独开启 latency-monitor |
支持查看高延迟命令 | 命令或后台操作耗时严重 |
| expired keys | expired_keys |
被动过期的 key 总数 | 频繁到期可能与业务周期有关 |
| CPU 占用 | used_cpu_sys, used_cpu_user, *_children |
Redis 主/子线程消耗 | 主线程长时间高耗可能是瓶颈 |
| 客户端等待 | blocked_clients |
阻塞命令客户端数(如 BLPOP) | 队列堆积或阻塞逻辑 |
| pub/sub 模式负载 | pubsub_channels, pubsub_patterns |
当前订阅频道数/通配数 | 多频道发布场景需关注此项 |
| backlog 长度 | repl_backlog_histlen |
主从复制 backlog 大小 | 长期为 backlog_size 说明复制繁忙 |
🔍 二、关键性能瓶颈指标详解
1. 命令执行效率
instantaneous_ops_per_sec: 当前 QPS
total_commands_processed: 累计命令数
-
分析建议:
-
结合 CPU 使用情况、client 数量、command type 做关联分析。
-
可与
MONITOR命令结合进行实时查看。
-
2. 查询命中率
keyspace_hits: 成功命中次数
keyspace_misses: 未命中次数
-
命中率计算:
hit_rate = hits / (hits + misses) -
命中率过低意味着:
-
key 不存在频率高
-
key 频繁过期
-
使用了错误的数据结构(例如大 key + 低频访问)
-
3. 内存淘汰监控
evicted_keys: 被主动淘汰 key 的数量
-
如果该值持续增长说明 Redis 处于“内存吃紧 + 触发 maxmemory 策略”状态。
-
需要关注:
-
maxmemory_policy是否合适? -
是否可增加内存或做冷热数据分层?
-
4. fork 性能指标
latest_fork_usec: 最近一次 fork 时间(微秒)
-
Redis 在执行 RDB 或 AOF rewrite 时会
fork(),如果该操作过慢(如 > 1 秒):-
会暂停主线程处理请求(短时间卡顿)
-
原因多为内存太大 → fork 过程页表复制消耗大
-
5. 延迟指标(需单独开启)
使用以下命令启用并分析 Redis 延迟:
CONFIG SET latency-monitor-threshold 100
LATENCY LATEST
LATENCY HISTOGRAM
-
可分析 slowlog 记录不到的“内部延迟”
-
特别适合排查 fork、AOF 写、RDB 保存引起的抖动
6. CPU 分析
used_cpu_sys / used_cpu_user
used_cpu_sys_children / used_cpu_user_children
-
主线程使用高:请求量大或单线程瓶颈
-
子线程高:说明 AOF 重写或 RDB 保存频繁
建议每分钟采集两次
used_cpu_xxx值,求差除时间间隔,得到准确 CPU 使用率
📈 三、性能监控最佳实践建议
| 场景 | 关注字段 |
|---|---|
| 缓存命中率低 | keyspace_hits / keyspace_misses |
| 内存高 + 淘汰多 | used_memory, evicted_keys, maxmemory_policy |
| 主从复制卡顿 | repl_backlog_histlen, master_repl_offset 差值 |
| fork 卡顿、写入慢 | latest_fork_usec, used_cpu_children 系列 |
| 命令积压或慢 | instantaneous_ops_per_sec, blocked_clients |
| Pub/Sub 过多 | pubsub_channels, pubsub_patterns |
| 网络堵塞 | instantaneous_output_kbps, backlog 变大 |
🛠 四、如何持续收集 INFO 性能数据(实用)
可用 shell 脚本/Prometheus 或 Python 收集核心指标:
redis-cli INFO stats | egrep 'evicted_keys|instantaneous_ops_per_sec|keyspace_hits|keyspace_misses|latest_fork_usec'
或者用 Python 每分钟轮询记录变化值做可视化。
✅ 结语
Redis INFO 的性能指标远比普通状态更重要,是监控、排障、优化的基础。
你可以据此做以下:
-
监控图表(Prometheus/Grafana)
-
性能基线比较(不同阶段/业务增长)
-
分析热点 key、命令结构问题(配合 SLOWLOG)
是否还希望我:
-
提供 Prometheus Redis Exporter 映射字段?
-
帮你设计一个基于这些指标的监控脚本?
-
分析你当前 Redis 的性能瓶颈(贴一下几个 INFO 输出)?
欢迎继续提问。
浙公网安备 33010602011771号