Skip to content
清晨的一缕阳光
返回

Redis 内存管理与优化

Redis 内存管理与优化

内存是 Redis 最宝贵的资源。合理的内存管理能提升性能、避免 OOM、降低成本。本文将深入 Redis 内存管理机制,分享优化技巧。

一、内存架构

1.1 内存模型

Redis 内存布局:
┌─────────────────────────────────────┐
│ 数据区                               │
│ - 键值对数据                         │
│ - 过期时间                           │
│ - 统计信息                           │
├─────────────────────────────────────┤
│ 缓冲区                               │
│ - 客户端输入缓冲                     │
│ - 客户端输出缓冲                     │
│ - 复制缓冲                           │
├─────────────────────────────────────┤
│ 内存碎片                             │
│ - 分配器开销                         │
│ - 碎片空间                           │
└─────────────────────────────────────┘

1.2 内存分配器

Redis 支持多种分配器:
- jemalloc(默认):碎片少,性能好
- libc:系统默认
- tcmalloc:Google 开发

查看分配器:
INFO memory | grep allocator

配置编译

# 使用 jemalloc
make MALLOC=jemalloc

# 使用 libc
make MALLOC=libc

# 使用 tcmalloc
make MALLOC=tcmalloc

二、内存使用分析

2.1 内存指标

INFO memory

# 关键指标
used_memory: 104857600          # Redis 分配内存
used_memory_rss: 125829120      # 操作系统分配内存
used_memory_peak: 157286400     # 峰值内存
used_memory_lua: 1024           # Lua 引擎内存
maxmemory: 2147483648           # 最大内存限制
maxmemory_human: "2.00G"
mem_fragmentation_ratio: 1.20   # 碎片率
mem_allocator: jemalloc         # 分配器

2.2 内存分析工具

# 内存统计
MEMORY STATS

# 输出示例
#  1) "peak.allocated"
#  2) (integer) 157286400
#  3) "total.allocated"
#  4) (integer) 104857600
#  5) "startup.allocated"
#  6) (integer) 1048576
#  7) "replication.backlog"
#  8) (integer) 1048576
#  9) "clients.slaves"
# 10) (integer) 0
# 11) "clients.normal"
# 12) (integer) 2097152
# 13) "aof.buffer"
# 14) (integer) 0
# 15) "lua.caches"
# 16) (integer) 0
# 17) "dbnum"
# 18) (integer) 1
# 19) "db.0"
# 20) (integer) 100000
# 21) "overhead.total"
# 22) (integer) 5242880
# 23) "keys.count"
# 24) (integer) 100000
# 25) "keys.bytes-per-key"
# 26) (integer) 1048
# 27) "dataset.bytes"
# 28) (integer) 99614720
# 29) "dataset.percentage"
# 30) "95.00%"
# 31) "peak.percentage"
# 32) "66.67%"

2.3 单 Key 内存分析

# 查看 Key 内存占用
MEMORY USAGE key

# 示例
MEMORY USAGE user:1001
# (integer) 1024  # 1KB

MEMORY USAGE large_list
# (integer) 10485760  # 10MB

2.4 大 Key 扫描

# 扫描大 Key
redis-cli --bigkeys

# 输出示例
# Scanning the entire keyspace...
#
# Biggest  string found so far '"key1"' with 1048576 bytes
# Biggest    list found so far '"key2"' with 10000 items
# Biggest   set found so far '"key3"' with 5000 items
# Biggest   hash found so far '"key4"' with 3000 items
# Biggest   zset found so far '"key5"' with 2000 items
#
# Summary:
# Total keys: 100000
# Total memory: 100MB
# Biggest key: key1 (1MB)

三、内存淘汰策略

3.1 淘汰策略配置

# 配置淘汰策略
maxmemory-policy allkeys-lru

# 可选策略
# noeviction: 不淘汰(写操作返回错误)
# allkeys-lru: 淘汰最近最少使用的键
# volatile-lru: 淘汰最近最少使用的有过期时间的键
# allkeys-random: 随机淘汰
# volatile-random: 随机淘汰有过期时间的键
# volatile-ttl: 淘汰剩余时间最短的键
# allkeys-lfu: 淘汰最不常用的键(Redis 4.0+)
# volatile-lfu: 淘汰最不常用的有过期时间的键

3.2 LRU 算法

Redis LRU 实现:
- 近似 LRU(不是完整 LRU)
- 随机采样优化
- 采样数量可配置

配置:
maxmemory-samples 10  # 采样数量(越大越精确,越小越 CPU 友好)

LRU 演进

Redis 2.8: 近似 LRU
Redis 3.0: 增加采样数量配置
Redis 4.0: 增加 LFU 策略

3.3 LFU 算法

# LFU 配置
maxmemory-policy allkeys-lfu
lfu-log-factor 10       # 对数因子
lfu-decay-time 1        # 衰减时间(分钟)

LFU vs LRU

LRU: 基于时间(最近使用)
LFU: 基于频率(最常使用)

场景:
- 热点数据稳定 → LFU
- 热点数据变化快 → LRU

3.4 淘汰监控

# 查看淘汰统计
INFO stats

# 输出示例
# evicted_keys: 1000      # 被淘汰的 Key 数量
# keyspace_hits: 4500000  # 命中数
# keyspace_misses: 500000 # 未命中数

# 实时查看淘汰
MONITOR | grep -E "DEL|EXPIRE"

四、内存碎片

4.1 碎片率计算

碎片率 = used_memory_rss / used_memory

理想值:1.0-1.1
> 1.5: 碎片过多
< 1.0: 可能使用 swap

4.2 碎片产生原因

1. 频繁修改值的大小
2. 删除大量 Key
3. 内存分配器特性
4. 长期运行未重启

4.3 碎片整理

主动碎片整理

activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100
active-defrag-cycle-min 1
active-defrag-cycle-max 25
active-defrag-max-scan-fields 1000

手动整理

# 重启 Redis(最彻底)
redis-cli SHUTDOWN
redis-server /etc/redis/redis.conf

# 内存诊断
MEMORY DOCTOR

# 输出示例
# Samplers: 10
# * High memory fragmentation detected
# * Consider enabling active defragmentation

五、内存优化技巧

5.1 数据结构优化

# 1. 使用 Hash 替代 String
# ❌ 不推荐
SET user:1001 '{"id":1001,"name":"John","age":25}'

# ✅ 推荐
HSET user:1001 id 1001 name John age 25
# 节省 ~40% 内存

内存对比

String (JSON): ~50 bytes + JSON 开销
Hash (ziplist): ~30 bytes

5.2 编码优化

# 查看编码
OBJECT ENCODING key

# 优化配置
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
zset-max-ziplist-entries 128
zset-max-ziplist-value 64

5.3 缩短 Key 名

# ❌ 不推荐
SET user:1001:profile:name "John"

# ✅ 推荐
SET u:1001:p:n "John"
# 或使用 Hash
HSET u:1001:p n "John"

节省计算

原始:user:1001:profile:name (22 字节)
优化:u:1001:p:n (9 字节)
节省:~60%

5.4 设置过期时间

# 临时数据设置过期
SET temp_key value EX 3600

# 批量设置过期
SCAN 0 MATCH temp:* COUNT 100
# 对每个 Key 设置 EXPIRE

5.5 避免大 Key

# 大 Key 危害:
# 1. 内存占用大
# 2. 操作慢
# 3. 网络传输慢
# 4. 删除阻塞

# 优化方案:
# 1. 拆分大 Key
# ❌ HSET large_hash field1 ... field10000
# ✅ 分片
HSET large_hash:0 field1 ... field1000
HSET large_hash:1 field1001 ... field2000

# 2. 使用合适的数据结构
# ❌ List 存储 10 万元素
# ✅ 分片或使用其他结构

5.6 定期清理

# 1. 清理过期数据
SCAN 0 MATCH temp:* COUNT 100
DEL temp:key

# 2. 清理无用数据
KEYS pattern:*  # 开发环境
DEL pattern:*

# 3. 使用 UNLINK(异步删除)
UNLINK large_key  # 非阻塞删除

六、监控与告警

6.1 监控指标

关键指标:
- used_memory / maxmemory: 内存使用率
- mem_fragmentation_ratio: 碎片率
- evicted_keys: 淘汰 Key 数
- expired_keys: 过期 Key 数

6.2 告警配置

# Prometheus 告警规则
- alert: RedisMemoryHigh
  expr: redis_memory_used_bytes / redis_max_memory_bytes > 0.9
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "Redis memory usage is high"

- alert: RedisFragmentationHigh
  expr: redis_mem_fragmentation_ratio > 1.5
  for: 10m
  labels:
    severity: warning
  annotations:
    summary: "Redis memory fragmentation is high"

- alert: RedisEvictionHigh
  expr: increase(redis_evicted_keys_total[5m]) > 100
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "Redis key eviction is high"

6.3 容量规划

容量规划步骤:
1. 统计当前内存使用
2. 预估增长趋势
3. 设置安全阈值(80%)
4. 提前扩容

示例:
当前:2GB,使用率 60%
月增长:10%
6 个月后:2GB * 1.6 = 3.2GB
建议配置:4GB

七、最佳实践

7.1 配置建议

# 内存配置
maxmemory 4gb
maxmemory-policy allkeys-lru
maxmemory-samples 10

# 碎片整理
activedefrag yes
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100

# 数据结构优化
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2

7.2 运维建议

日常运维:
1. 监控内存使用率
2. 定期扫描大 Key
3. 分析内存碎片
4. 清理过期数据
5. 容量规划

定期任务:
- 每周:大 Key 扫描
- 每月:内存分析
- 每季:容量评估

7.3 故障处理

# 内存 OOM
# 1. 临时增加内存
CONFIG SET maxmemory 8gb

# 2. 清理数据
MEMORY DOCTOR
UNLINK large_key

# 3. 重启(最后手段)
redis-cli SHUTDOWN
redis-server

总结

Redis 内存管理核心要点:

优化方向关键配置效果
淘汰策略maxmemory-policy避免 OOM
碎片整理activedefrag减少浪费
数据结构Hash vs String节省 40%
Key 命名缩短 Key 名节省 60%
过期清理EXPIRE自动释放

最佳实践

  1. 合理设置 maxmemory
  2. 选择合适的淘汰策略
  3. 启用主动碎片整理
  4. 优化数据结构
  5. 定期扫描大 Key
  6. 监控内存指标

掌握内存管理,高效使用 Redis!

参考资料


分享这篇文章到:

上一篇文章
Redis 最佳实践总结
下一篇文章
Redis 数据恢复与迁移实战