Redis 作为纯内存数据库,内存不仅是数据存储介质,更是决定服务可用性的核心资源。一个 64GB 内存的 Redis 节点,可能实际存储的有效数据不足 40GB,剩余空间被内部分配器开销、数据结构元数据、内存碎片以及过期键残留所吞噬。理解 Redis 内存管理的底层机制,是在生产环境中避免 OOM、控制成本、提升容量的必修课。
本文将从内存分配器的选择开始,逐步深入到碎片治理、编码优化、驱逐策略、监控诊断与线上排障的全过程,帮助你构建一套可落地的 Redis 内存治理方案。
一、Redis 内存分配器:jemalloc、glibc malloc 与 tcmalloc
Redis 在编译时需要选择一个内存分配器,默认使用 jemalloc。不同的分配器在高并发场景下的吞吐、碎片率和 CPU 占用差异巨大。
1.1 Redis 支持的三种分配器
| 分配器 | 默认启用 | 特点 | 适用场景 |
|---|---|---|---|
| jemalloc | 是(Redis 默认) | 多线程友好、按 size-class 管理、碎片率较低 | 生产环境首选 |
| glibc malloc(ptmalloc2) | 编译可选 | 单线程表现好,多线程竞争加剧、碎片率高 | 简单场景或兼容性测试 |
| tcmalloc | 编译可选 | Google 出品,小对象分配极快,中等碎片 | CPU 密集型、多线程读取频繁 |
jemalloc 被 Redis 作者 Salvatore Sanfilippo 选为默认分配器,核心原因是它在多线程高并发分配/释放场景中表现稳定。Redis 虽然主线程是单线程的,但后台存在 RDB、AOF rewrite、lazy free 等线程,jemalloc 的 arena 隔离设计能显著降低锁竞争。
1.2 jemalloc 的 size-class 机制
jemalloc 将内存按固定大小分级(size class),常见级别包括 8、16、32、48、64、80、96、112、128 … 一直增长到 2KB,再大则按页(4KB)对齐分配。
请求 45 字节 → 分配到 48 bytes 的 size class
请求 100 字节 → 分配到 112 bytes 的 size class
请求 3000 字节 → 分配到 4KB 的页级别
这意味着:Redis 中的每个 key、value、以及内部数据结构,其实际占用的内存都会被对齐到最近的 size class。一个 20 字节的字符串,实际占用 32 字节;一个 60 字节的 hash 字段,实际占用 64 字节。这种对齐带来的内存内耗虽小,但在上亿 key 的场景下不可忽视。
1.3 编译时切换分配器
# 默认使用 jemalloc
make
# 使用 glibc malloc
make MALLOC=libc
# 使用 tcmalloc(需先安装 gperftools)
make MALLOC=tcmalloc
生产环境强烈建议使用默认的 jemalloc,除非你有明确的性能压测数据支撑其他方案。
1.4 jemalloc 统计信息查看
Redis 编译时启用 jemalloc 后,可通过 MALLOC: 段落查看分配器级别的统计:
redis-cli INFO memory | grep -A 10 "MALLOC:"
# 输出示例:
# MALLOC: 26713328 (allocator active)
# MALLOC: 22345616 (allocator allocated)
# MALLOC: 4367712 (allocator resident)
这些指标与 Redis 进程 RSS(resident set size)之间的关系构成了分析内存碎片的关键数据。
二、内存碎片与主动碎片整理(Active Defrag)
2.1 内存碎片的成因
内存碎片(Fragmentation)分为内部碎片和外部碎片两类:
- 内部碎片:jemalloc size-class 对齐导致的浪费,如请求 45 字节实际分配 48 字节,浪费 3 字节。
- 外部碎片:内存反复分配和释放后,已释放的小块内存散布在已分配块之间,导致虽然空闲内存总量足够,但没有连续大块可供分配。Redis 的场景中,key 过期淘汰后留下的空隙就是典型的外部碎片来源。
2.2 碎片率的计算
Redis 通过 INFO memory 报告碎片率指标:
redis-cli INFO memory
# 重点关注以下指标:
# used_memory: 已用内存(由 Redis 自行统计的数据结构占用)
# used_memory_rss: 操作系统视角的进程常驻内存(RSS)
# mem_fragmentation_ratio = used_memory_rss / used_memory
| 碎片率范围 | 含义 | 处理建议 |
|---|---|---|
| < 1.0 | RSS 小于 Redis 统计值( rarely,可能是 swap 或内存未加载) | 检查 swap 使用 |
| 1.0 - 1.5 | 健康范围 | 正常 |
| 1.5 - 2.0 | 轻度碎片 | 关注趋势,考虑开启主动整理 |
| > 2.0 | 严重碎片 | 必须开启 active defrag 或 dump 后重启 |
2.3 主动碎片整理(Active Defragmentation)
Redis 4.0 引入主动碎片整理功能,由后台线程运行,在线将分散的数据拷贝到新的连续内存位置,从而合并空闲块。其核心原理类似于 JVM 的标记-复制(mark-copy)算法,但 Redis 版本只对部分数据结构生效。
配置参数
# redis.conf
# 开启主动碎片整理(默认关闭)
activedefrag yes
# 碎片率达到多少时开始整理
active-defrag-threshold-lower 10
# 碎片率达到多少时最大化整理力度
active-defrag-threshold-upper 100
# 整理时最多占用 CPU 百分比
active-defrag-cycle-min 5
active-defrag-cycle-max 75
# 整理时每次扫描的最大 key 数量
active-defrag-max-scan-fields 1000
启用建议
# 动态开启(无需重启)
redis-cli CONFIG SET activedefrag yes
redis-cli CONFIG SET active-defrag-threshold-lower 10
# 监控整理进度
redis-cli INFO stats | grep defrag
# active_defrag_hits: key 被移动到新内存位置的次数
# active_defrag_misses: 尝试移动但失败的次数
# active_defrag_key_hits: 被整理的 key 数量
注意:主动碎片整理只在分配器为 jemalloc 且 Redis 编译时启用了 --enable-active-defrag 时可用。该过程会额外消耗 CPU,应在业务低峰期开启或在从节点上先行验证。
2.4 非 active defrag 的碎片治理方案
如果 Redis 版本低于 4.0,或未启用 active defrag,仍有以下手段:
- 通过 RDB 重启恢复:
BGSAVE生成 RDB,重启 Redis 加载,内存将被重新紧凑分配。 - 原地重建:使用
DEBUG RELOAD(仅限测试环境)或主从切换后重建从节点。 - 控制数据淘汰节奏:避免突发大量 key 过期,改为均匀过期或使用
expire分散 TTL。
三、内存优化策略:编码、阈值与共享对象
3.1 底层编码演进:ziplist → listpack
Redis 在数据量较小时,会使用紧凑的编码格式来降低内存占用。这一机制对理解内存暴涨尤为关键。
| 数据类型 | 小数据量编码 | 大数据量编码 | 转换阈值相关配置 |
|---|---|---|---|
| String | RAW / INT | RAW / INT | 无 |
| List | ziplist (Redis < 7.0) / listpack (Redis 7.0+) | quicklist | list-max-ziplist-size / list-max-listpack-size |
| Hash | ziplist / listpack | hashtable | hash-max-ziplist-entries / hash-max-listpack-entries |
| Set | intset | hashtable | set-max-intset-entries |
| ZSet | ziplist / listpack | skiplist + dict | zset-max-ziplist-entries / zset-max-listpack-entries |
ziplist 的结构特点
ziplist 是一个连续的内存块,entry 之间没有指针,通过上一项长度字段实现双向遍历。每个 entry 的元数据极少:
| <zlbytes> | <zltail> | <zllen> | <entry1> | <entry2> | ... | <entryN> | <zlend> |
| 4 bytes | 4 bytes | 2 bytes | | | | | 1 byte |
相比 hashtable(dict),ziplist 没有 dictEntry、没有两个哈希表指针、没有渐进式 rehash 的冗余空间,内存节省通常在 50% 以上。
listpack 是什么
Redis 7.0 用 listpack 取代了 ziplist,解决了 ziplist 的级联更新问题(修改 entry 时前一项长度字段可能连锁变化)。listpack 每个 entry 只记录自己的长度,不再记录前一项长度,结构更安全,内存占用与 ziplist 基本持平。
3.2 配置优化:提高紧凑编码的阈值
如果你的业务中 Hash 和 ZSet 的平均元素数量可控,可以适当放宽阈值,让更多数据保持在 listpack/ziplist 编码:
# redis.conf —— 根据业务特征调整
hash-max-listpack-entries 1024 # 默认 512,提高后更多 Hash 保持紧凑编码
hash-max-listpack-value 128 # 单个字段值超过 128 字节则升级为 hashtable
zset-max-listpack-entries 256 # 默认 128
zset-max-listpack-value 128
list-max-listpack-size -2 # quicklist 中每个 listpack 的最大 size
⚠️ 警告:阈值过高会导致单个 ziplist/listpack 过大,引发 BigKey 问题。修改前应在从节点上压测 LPUSH、HSET 等操作的延迟变化。
3.3 整数共享对象(Shared Integers)
Redis 预先创建了一批共享对象,范围默认是 0 到 9999:
// Redis 源码中的 shared integers
shared.integers = zmalloc(sizeof(robj*) * (REDIS_SHARED_INTEGERS));
for (j = 0; j < REDIS_SHARED_INTEGERS; j++) {
shared.integers[j] = createObject(OBJ_STRING, (void*)(long)j);
shared.integers[j]->encoding = OBJ_ENCODING_INT;
}
这意味着:如果你的 String value 是数字且在 0~9999 范围内,Redis 直接返回共享对象的指针,不分配新内存。这在计数器、状态码、用户 ID 等场景中能显著降低内存占用。
对于超出范围的整数,可使用 OBJECT ENCODING key 查看实际编码:
redis-cli SET counter 42
redis-cli OBJECT ENCODING counter
# "int" —— 使用共享整数,几乎零额外内存
redis-cli SET uid 12345678
redis-cli OBJECT ENCODING uid
# "int" —— 仍然使用整数编码(非共享),比 RAW 字符串省内存
3.4 Hash 的 field-value 优化实战
社交场景中存储用户 profile 是典型的 Hash 使用场景。假设有 1000 万用户,每个用户有 10 个字段:
# 方案 A:每个用户一个 Hash
HSET user:1001 name "Alice" age 25 city "Beijing"
# 1000 万 Hash × 10 字段 → 内存占用取决于编码
# 方案 B:每个字段一个 String
SET user:1001:name "Alice"
SET user:1001:age 25
# 1000 万 × 10 = 1 亿个 key → 每个 key 的 dictEntry 开销约 64 字节,总计额外消耗 ~6.4GB
方案 A 在字段数小于 hash-max-listpack-entries 时,整个 Hash 以 listpack 紧凑存储;方案 B 每个 key 都有独立的 redisObject + dictEntry + sds 开销。通过 redis-cli --big-keys 或 MEMORY USAGE 验证可知:
redis-cli MEMORY USAGE user:1001
# 返回该 key 及其 value 的近似总字节数
四、内存开销分析:结构、指针与对齐
4.1 Redis Object(redisObject)的开销
每一个被存储的 value,不论类型,都被包装在一个 redisObject 中:
typedef struct redisObject {
unsigned type:4; // 数据类型:string/list/hash/set/zset等
unsigned encoding:4; // 底层编码
unsigned lru:LRU_BITS; // LRU/LFU 时钟信息(24bits)
int refcount; // 引用计数
void *ptr; // 指向实际数据结构的指针
} robj;
在 64 位系统上,redisObject 大小为 16 字节。这 16 字节是每个 value 无法避免的基础开销。
4.2 Dict Entry 的开销
Redis 使用哈希表(dict)管理所有 key。每个 key-value 对在 dict 中对应一个 dictEntry:
typedef struct dictEntry {
void *key; // 指向 key 的 sds
union {
void *val; // 指向 redisObject
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next; // 链地址法解决冲突
} dictEntry;
64 位系统下 dictEntry 约 24 字节(key 指针 + val 联合体 + next 指针)。再加上 key 本身的 sds(约 9 字节 + key 长度对齐),一个空 value 的 String 实际内存约为:
dictEntry: 24 bytes
redisObject: 16 bytes
sds header: ~9 bytes
key 内容: strlen(key) bytes,对齐到 size class
value 内容: 0 ~ N bytes
总计: ~50 + strlen(key) + value_size(含对齐)
4.3 内存对齐与填充(Padding)
由于 jemalloc 的 size-class 对齐和 C 结构体的自然对齐,实际内存往往大于理论值。以存储一个 key 为 "uid:12345"(9 字节)、value 为 "1"(1 字节)的 String 为例:
| 组件 | 原始大小 | 对齐后大小 | 说明 |
|---|---|---|---|
| key 的 sds | 9+1=10 | 16 | sds header 3-9 字节 + 内容,对齐到 16 |
| dictEntry | 24 | 32 | 对齐到 32 字节 size class |
| redisObject | 16 | 16 | 恰好对齐 |
| value sds | 1+1=2 | 8 | 对齐到 8 字节 |
| 理论总计 | 52 | 72 | 有效数据 10 字节,开销 62 字节 |
这个例子说明:Redis 中小 key-value 的元数据开销可能远大于数据本身。 当缓存的是大量小对象(如用户 session、计数器)时,这是必须考虑的因素。
4.4 使用 MEMORY USAGE 精确分析
Redis 4.0 引入 MEMORY USAGE 命令,可以分析单个 key 的内存:
# 查看 key 的总内存占用(含 value 和所有嵌套结构)
redis-cli MEMORY USAGE user:1001
# (integer) 184
# 查看抽样分析,samples 参数控制子元素采样数(对 Hash/List/Set/ZSet 有效)
redis-cli MEMORY USAGE user:1001 SAMPLES 5
# (integer) 184
对于全局统计,使用 MEMORY STATS:
redis-cli MEMORY STATS
# 1) "peak.allocated"
# 2) (integer) 104857600
# 3) "total.allocated"
# 4) (integer) 94371840
# 5) "startup.allocated"
# 6) (integer) 4325376
# ... 后续条目覆盖词典、用户数据、客户端输出缓冲区等
五、maxmemory 配置与内存驱逐策略
5.1 maxmemory 基础配置
Redis 通过 maxmemory 参数限制最大可用内存。当数据达到上限时,根据 maxmemory-policy 决定如何回收空间。
# redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru
maxmemory 的计数标准是 Redis 自己统计的 used_memory,而非操作系统 RSS。因此即使 used_memory_rss 超过 maxmemory,只要 used_memory 未触发阈值,驱逐就不会发生。
| 参数 | 说明 |
|---|---|
maxmemory 0 | 不限制内存,直到系统 OOM(默认,生产环境严禁) |
maxmemory <bytes> | 精确字节限制 |
maxmemory 2gb | 支持带单位的人类可读格式 |
5.2 八种驱逐策略详解
| 策略名称 | 作用范围 | 淘汰逻辑 | 适用场景 |
|---|---|---|---|
noeviction | 全部 | 不淘汰,直接返回 OOM 错误 | 数据不可丢的持久存储场景 |
allkeys-lru | 全部 key | 近似 LRU 淘汰整个 key | 通用缓存场景,最常用 |
allkeys-lfu | 全部 key | 近似 LFU 淘汰访问频次最低的 key | 存在热点差异的缓存 |
allkeys-random | 全部 key | 随机淘汰 | 均匀访问分布的缓存 |
volatile-lru | 仅含 TTL 的 key | 近似 LRU 淘汰 | 部分数据需持久保留 |
volatile-lfu | 仅含 TTL 的 key | 近似 LFU 淘汰 | 含 TTL 数据有冷热差异 |
volatile-random | 仅含 TTL 的 key | 随机淘汰 | 含 TTL 数据均匀访问 |
volatile-ttl | 仅含 TTL 的 key | 淘汰 TTL 最短的 key | 希望尽快释放即将过期数据 |
LRU vs LFU 的选择建议
- LRU(Least Recently Used):假设"最近被访问的数据更可能被再次访问"。适用于访问具有时间局部性的业务,如首页推荐、实时榜单。
- LFU(Least Frequently Used):假设"访问频次高的数据更有价值"。适用于存在长期热点的业务,如热门商品、核心配置。
Redis 的 LRU/LFU 都是近似实现,通过 24 位的 lru 字段计时,节省内存但非精确。
5.3 驱逐策略的动态切换
# 运行时调整策略
redis-cli CONFIG SET maxmemory-policy allkeys-lfu
# 查看当前策略
redis-cli CONFIG GET maxmemory-policy
# 1) "maxmemory-policy"
# 2) "allkeys-lfu"
切换策略不会导致数据丢失(除了触发新策略的淘汰),但策略改变后淘汰行为立即生效。
5.4 OOM 处理:当驱逐来不及释放空间时
在以下场景中,即使配置了驱逐策略,Redis 仍可能面临 OOM:
- 写入速度远超淘汰速度:例如 pipeline 批量写入百万级 key,而淘汰是逐 key 进行的。
- 大 key 一次性写入:单个 key 的 value 大小超过剩余可用内存。
- 缓冲区暴涨:客户端输出缓冲区(client-output-buffer-limit)或复制积压缓冲区(repl-backlog)占用大量内存。
此时 Redis 的行为取决于策略:
noeviction:返回错误(error) OOM command not allowed when used memory > 'maxmemory'- 其他策略:尝试淘汰后继续执行,若淘汰后仍不足,同样返回 OOM 错误
生产建议:
# 在 maxmemory 达到 80% 时触发告警,预留 20% 缓冲
# 通过监控告警 + 扩容,避免进入被动驱逐状态
# 限制客户端输出缓冲区,防止从节点慢同步导致主节点 OOM
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
六、内存监控命令与诊断工具
6.1 INFO memory 全面解读
redis-cli INFO memory
核心指标解读:
| 指标 | 含义 | 诊断价值 |
|---|---|---|
used_memory | Redis 自行统计的数据结构内存 | 与 maxmemory 比较判断驱逐线 |
used_memory_rss | 操作系统 RSS | 与 used_memory 比较判断碎片率 |
used_memory_peak | 历史峰值 | 评估容量规划 |
used_memory_lua | Lua 脚本引擎占用 | 大量 EVAL 时关注 |
mem_fragmentation_ratio | RSS / used_memory | 碎片率核心指标 |
mem_allocator | 当前分配器 | 确认是否 jemalloc |
active_defrag_running | 主动整理是否运行 | 0 = 未运行,1+ = 正在运行 |
lazyfree_pending_objects | 后台异步释放的对象数 | 大量 DEL/UNLINK 后观察 |
6.2 MEMORY DOCTOR 诊断建议
Redis 4.0 提供 MEMORY DOCTOR 命令,自动分析内存状况并给出建议:
redis-cli MEMORY DOCTOR
# 可能的输出:
# "Hi Sam, I can't find any memory issue in your instance."
# 或
# "# High fragmentation: 83% of memory is wasted..."
# "# Big user keys detected..."
该命令通过启发式规则判断问题,适合快速初筛,但不替代人工深度分析。
6.3 MEMORY PURGE:释放已归还分配器但未释放给 OS 的内存
jemalloc 在释放内存后,可能将内存保留在 arena 中而不立即归还给操作系统。这会导致 RSS 持续高于实际使用。Redis 提供 MEMORY PURGE 命令强制 jemalloc 执行 arena.<i>.purge:
redis-cli MEMORY PURGE
# 执行后观察 used_memory_rss 是否下降
6.4 大 key 扫描:内存暴涨的首要嫌疑
# 扫描大 key(阻塞式,谨慎在大实例使用)
redis-cli --big-keys
# 渐进式扫描(非阻塞,推荐用于生产)
redis-cli --scan --pattern "*" | head -n 1000 | \
xargs -I {} sh -c 'echo "{}: $(redis-cli MEMORY USAGE {})"'
# 使用 RDB 工具离线分析(推荐)
rdb -c memory /var/lib/redis/dump.rdb > memory.csv
sort -t, -k4 -nr memory.csv | head -n 20
6.5 内存占用趋势监控脚本
#!/bin/bash
# redis-memory-monitor.sh —— 每 60 秒采集一次内存指标
HOST="localhost"
PORT="6379"
LOG="/var/log/redis-memory.log"
while true; do
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
INFO=$(redis-cli -h $HOST -p $PORT INFO memory)
USED=$(echo "$INFO" | grep "^used_memory:" | cut -d: -f2 | tr -d '\r')
RSS=$(echo "$INFO" | grep "^used_memory_rss:" | cut -d: -f2 | tr -d '\r')
RATIO=$(echo "$INFO" | grep "^mem_fragmentation_ratio:" | cut -d: -f2 | tr -d '\r')
PEAK=$(echo "$INFO" | grep "^used_memory_peak:" | cut -d: -f2 | tr -d '\r')
echo "$TIMESTAMP,used=$USED,rss=$RSS,ratio=$RATIO,peak=$PEAK" >> $LOG
sleep 60
done
七、生产场景:内存暴涨排查实战
7.1 场景一:BigKey 导致内存飙升
现象:内存使用量从 10GB 突增至 18GB,碎片率正常。
排查步骤:
# 步骤 1:确认内存增长来源
redis-cli INFO memory | grep -E "used_memory|used_memory_rss"
# 步骤 2:扫描大 key
redis-cli --big-keys
# 步骤 3:定位到具体 key 后分析结构
redis-cli DEBUG OBJECT big_key
# 输出:value at:0x7f8b4c0b8000 refcount:1 encoding:hashtable serializedlength:5242880 lru:12345678 lru_seconds_idle:3600
# 步骤 4:查看元素数量
redis-cli HLENS big_key
redis-cli LLEN big_key
# 步骤 5:使用 UNLINK 异步删除(Redis 4.0+),避免阻塞
redis-cli UNLINK big_key
根因:应用端将用户行为日志以 List 形式聚合写入单个 key,未做分片,导致 List 元素突破千万级。解决方案是将日志按用户 ID 取模分散到 100 个 List。
7.2 场景二:内存碎片率大于 2.0
现象:used_memory 20GB,used_memory_rss 45GB,碎片率 2.25。
排查步骤:
# 确认分配器类型
redis-cli INFO memory | grep mem_allocator
# mem_allocator:jemalloc-5.2.1
# 查看 jemalloc 统计
redis-cli INFO memory | grep -A 5 "MALLOC:"
# 开启主动碎片整理
redis-cli CONFIG SET activedefrag yes
redis-cli CONFIG SET active-defrag-cycle-min 10
redis-cli CONFIG SET active-defrag-cycle-max 50
# 观察整理进度
watch -n 5 'redis-cli INFO stats | grep defrag'
根因:业务执行了大量 SREM、HDEL 和 EXPIRE 操作,哈希表缩容和 key 过期释放导致外部碎片严重。开启 active defrag 后 2 小时内 RSS 降至 28GB,碎片率恢复至 1.4。
7.3 场景三:maxmemory 达到上限但驱逐不生效
现象:写入报错 OOM,但 INFO keyspace 显示有大量 key 已设置 TTL。
排查:
redis-cli CONFIG GET maxmemory-policy
# 1) "maxmemory-policy"
# 2) "noeviction"
根因:某次配置变更时误将 maxmemory-policy 设为 noeviction,导致内存满后直接拒绝写入。修正为 allkeys-lru 后恢复正常。
7.4 场景四:复制积压缓冲区占用过高
现象:主节点内存持续增长,used_memory 超出数据量预期 2GB,且无 BigKey。
redis-cli INFO replication | grep repl_backlog
# repl_backlog_active:1
# repl_backlog_size:2147483648 # 2GB
# repl_backlog_first_byte_offset:1234567890
# repl_backlog_histlen:2147483642
根因:repl-backlog-size 被设为 2GB,在从节点网络抖动频繁时,主节点维持巨大的复制积压缓冲区。将其调整为 256MB,并优化从节点的网络稳定性后,内存占用回归正常。
7.5 场景五:Lua 脚本缓存泄漏
现象:used_memory_lua 持续增长,而业务数据量无变化。
redis-cli INFO memory | grep lua
# used_memory_lua: 52428800 # 50MB Lua 缓存
# 查看已加载脚本数量
redis-cli SCRIPT EXISTS $(redis-cli SCRIPT DEBUG)
redis-cli SCRIPT FLUSH
# 清空后 used_memory_lua 恢复基线
根因:应用在每次请求时动态生成唯一的 Lua 脚本(包含时间戳或随机数),导致 Redis 的 Lua 脚本缓存无限增长。解决方案是将脚本参数化,使用固定的 SHA 加载。
八、内存管理最佳实践总结
| 维度 | 建议 |
|---|---|
| 分配器 | 始终使用默认 jemalloc,不自行切换 |
| 碎片治理 | Redis 4.0+ 开启 active defrag;低版本定期 RDB 重启 |
| 编码优化 | 根据业务特征调整 listpack/ziplist 阈值;优先使用 Hash 聚合小字段 |
| 驱逐策略 | 缓存场景用 allkeys-lru 或 allkeys-lfu;核心数据用 volatile-lru 并加 TTL |
| maxmemory | 必须显式配置,设置为物理内存的 70%~80%,预留缓冲 |
| 监控告警 | 监控 used_memory、fragmentation_ratio、evicted_keys 趋势 |
| 大 key 治理 | 建立 BigKey 扫描流程,List/Hash/ZSet/Set 元素数超过 10 万需拆分 |
| 复制缓冲 | 根据从节点数量和网络质量调整 repl-backlog-size |
| Lua 脚本 | 脚本参数化,避免动态生成唯一脚本导致缓存泄漏 |
九、相关文章
- Redis 数据结构深度解析:SDS、ziplist、skipList 与编码转换 —— 理解 ziplist/listpack/quicklist 的底层实现
- Redis 缓存设计模式:Cache Aside、穿透/击穿/雪崩防御 —— 缓存架构设计与一致性问题
- Redis 高可用架构:主从复制、Sentinel 故障转移与 Cluster 分片 —— 复制积压缓冲区与主从内存关联分析
- Redis 生产安全指南:ACL 权限、TLS 加密与审计日志 —— 生产环境安全配置
内存是 Redis 最宝贵的资源,也是最容易被忽视的隐患。从分配器的选择到碎片的治理,从编码优化到驱逐策略的落地,每一步都直接影响服务的稳定性与成本。希望本文能为你的 Redis 内存治理提供系统性的思路与可执行的方案。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。