一、Redis内存为什么会悄悄膨胀

Redis作为内存数据库,内存占用过高是常见问题。我们先看看内存都去哪了:

  1. 键值对本身占用的空间
  2. Redis维护数据结构需要的额外内存
  3. 客户端缓冲区
  4. 持久化时的AOF缓冲区
  5. 主从复制时的复制缓冲区

举个例子,我们存了100万个键值对,每个键值对看起来很小,但加起来就很可观了:

# Redis技术栈示例
# 存储100万个简单的键值对
SET user:1 "张三"
SET user:2 "李四"
...
SET user:1000000 "王五"

这些数据看起来不大,但Redis为每个键值对都会分配额外空间来维护数据结构,实际内存占用可能是原始数据的2-3倍。

二、编码优化 - 让数据更苗条

Redis提供了多种编码方式来优化内存使用,我们可以根据数据类型选择合适的编码。

1. 字符串优化

对于短字符串,使用embstr编码更省空间:

# 短字符串会自动使用embstr编码
SET short_str "hello"  # 占用更少内存
SET long_str "这是一个很长的字符串..." # 使用raw编码

2. 哈希优化

当哈希字段较少时,使用ziplist编码更高效:

# 配置哈希使用ziplist编码的阈值
CONFIG SET hash-max-ziplist-entries 512  # 字段数少于512时使用ziplist
CONFIG SET hash-max-ziplist-value 64     # 字段值小于64字节时使用ziplist

# 示例哈希
HSET user:1000 name "张三" age 30 city "北京"

3. 列表优化

对于小型列表,ziplist也是不错的选择:

# 配置列表使用ziplist的阈值
CONFIG SET list-max-ziplist-entries 512
CONFIG SET list-max-ziplist-value 64

# 示例列表
LPUSH recent_users "user1" "user2" "user3"

4. 集合优化

小集合使用intset编码可以节省大量空间:

# 配置集合使用intset的阈值
CONFIG SET set-max-intset-entries 512

# 示例集合
SADD user:1000:tags 1 2 3 4 5

三、淘汰策略 - 给内存设置安全线

当内存不足时,Redis提供了多种淘汰策略,我们需要根据业务特点选择合适的策略。

1. 常用淘汰策略

# 查看当前淘汰策略
CONFIG GET maxmemory-policy

# 设置淘汰策略(常用以下几种)
CONFIG SET maxmemory-policy volatile-lru    # 对设置了过期时间的键使用LRU算法
CONFIG SET maxmemory-policy allkeys-lru     # 对所有键使用LRU算法
CONFIG SET maxmemory-policy volatile-ttl    # 淘汰即将过期的键
CONFIG SET maxmemory-policy noeviction      # 不淘汰,返回错误(默认)

2. 策略选择建议

  • 缓存场景: volatile-lru 或 allkeys-lru
  • 持久化存储: noeviction 但要确保有足够内存
  • 混合使用: 可以为不同数据库设置不同策略

3. 实际配置示例

# 设置最大内存限制
CONFIG SET maxmemory 2gb

# 设置淘汰策略为volatile-lru
CONFIG SET maxmemory-policy volatile-lru

# 设置键的过期时间
SET session:user1 "data" EX 3600  # 1小时后过期

四、实战技巧 - 综合优化方案

1. 数据分片

将大键拆分为多个小键:

# 原始大哈希
HSET big_hash field1 "value1" ... field1000 "value1000"

# 优化为分片哈希
HSET hash:part1 field1 "value1" ... field100 "value100"
HSET hash:part2 field101 "value101" ... field200 "value200"
...

2. 使用更高效的数据类型

# 字符串存储多个ID(不推荐)
SET user:friends:1000 "1,2,3,4,5..."

# 使用集合存储更高效(推荐)
SADD user:friends:1000 1 2 3 4 5...

3. 定期清理无用数据

# 查找大键
redis-cli --bigkeys

# 扫描并删除过期键(定期执行)
redis-cli SCAN 0 COUNT 1000

4. 监控与预警

# 查看内存使用情况
INFO memory

# 关键指标
used_memory_human: 显示已用内存
mem_fragmentation_ratio: 内存碎片率

五、应用场景与注意事项

1. 适用场景

  • 缓存系统
  • 会话存储
  • 排行榜/计数器
  • 消息队列(轻量级)

2. 技术优缺点

优点:

  • 显著减少内存使用
  • 提高系统稳定性
  • 延长硬件使用寿命

缺点:

  • 需要根据业务特点调优
  • 过度优化可能影响性能
  • 需要持续监控和维护

3. 注意事项

  1. 不要盲目追求最小内存,要兼顾性能
  2. 生产环境修改配置前先测试
  3. 监控内存碎片率,过高时需要重启
  4. 大集群中不同节点可能需要不同配置
  5. 记得备份重要配置

六、总结

Redis内存优化是个持续的过程,需要:

  1. 了解数据特点
  2. 选择合适的编码方式
  3. 配置合理的淘汰策略
  4. 建立监控机制
  5. 定期review和调整

记住,没有放之四海而皆准的最优配置,最适合你业务的配置才是最好的。