外观
Redis 内存管理
Redis 是一个内存数据库,内存管理是 Redis 运维的核心任务之一。有效的内存管理可以提高 Redis 性能、降低成本、避免内存溢出等问题。本文档将详细介绍 Redis 内存管理的各个方面,包括内存结构、内存使用统计、内存配置优化、内存淘汰策略、内存碎片管理和大键管理等。
Redis 内存结构
1. 内存使用分类
Redis 内存主要分为以下几个部分:
- 数据内存:存储 Redis 数据的内存,包括键值对、数据结构等
- 进程内存:Redis 进程本身占用的内存,包括代码段、数据段、堆内存等
- 缓冲区内存:包括客户端缓冲区、复制缓冲区、AOF 缓冲区等
- 内存碎片:由于内存分配和释放导致的内存碎片
2. 数据内存
数据内存是 Redis 内存的主要组成部分,用于存储 Redis 数据。Redis 支持多种数据结构,每种数据结构的内存使用方式不同:
- 字符串(String):简单的键值对存储
- 哈希(Hash):字段值对的集合
- 列表(List):有序的字符串列表
- 集合(Set):无序的字符串集合
- 有序集合(Sorted Set):有序的字符串集合,每个元素带有分数
- 流(Stream):日志型数据结构
- 位图(Bitmap):二进制位操作
- 基数统计(HyperLogLog):基数估算
- 地理空间(Geo):地理位置数据
3. 缓冲区内存
缓冲区内存主要包括以下几种:
- 客户端缓冲区:每个客户端连接都有输入缓冲区和输出缓冲区
- 复制缓冲区:主从复制时使用的缓冲区,包括复制积压缓冲区和复制客户端缓冲区
- AOF 缓冲区:AOF 持久化时使用的缓冲区,包括 AOF 写入缓冲区和 AOF 重写缓冲区
4. 内存碎片
内存碎片是由于内存分配和释放导致的内存不连续现象。Redis 会产生内存碎片的原因包括:
- 频繁的键值对增删:导致内存分配和释放频繁
- 不同大小的键值对:导致内存分配的块大小不一致
- 内存分配器的特性:不同的内存分配器(如 jemalloc、glibc)产生的内存碎片情况不同
内存使用统计
1. INFO memory 命令
使用 INFO memory 命令可以获取 Redis 内存使用的详细统计信息:
bash
redis-cli info memory主要输出项包括:
used_memory:Redis 分配器分配的内存总量used_memory_rss:Redis 进程占用的物理内存总量used_memory_peak:Redis 内存使用的峰值used_memory_lua:Lua 脚本引擎占用的内存mem_fragmentation_ratio:内存碎片率,used_memory_rss / used_memorymem_allocator:Redis 使用的内存分配器
2. 内存使用分析
2.1 内存碎片率分析
bash
# 查看内存碎片率
redis-cli info memory | grep mem_fragmentation_ratio
# 理想碎片率:1.0-1.5
# 高碎片率:>1.5
# 低碎片率:<1.0(可能存在内存交换)2.2 数据内存分析
bash
# 查看数据内存使用情况
redis-cli info memory | grep used_memory_dataset2.3 客户端缓冲区分析
bash
# 查看客户端连接数
redis-cli info clients | grep connected_clients
# 查看客户端输入缓冲区最大使用量
redis-cli info clients | grep instantaneous_input_kbps
# 查看客户端输出缓冲区最大使用量
redis-cli info clients | grep instantaneous_output_kbps3. 内存使用监控
3.1 实时监控
bash
# 每秒监控一次内存使用情况
watch -n 1 'redis-cli info memory | grep -E "used_memory|used_memory_rss|mem_fragmentation_ratio"'3.2 持久化监控
使用 Prometheus + Grafana 等监控工具进行持久化监控,设置内存使用告警阈值。
内存配置优化
1. 最大内存配置
txt
# redis.conf
# 设置 Redis 最大使用内存(字节)
maxmemory 1gb
# 或使用单位表示
maxmemory 1024mb
maxmemory 2gb2. 内存分配器配置
txt
# redis.conf
# 设置内存分配器(默认 jemalloc)
# 可选值:jemalloc, glibc, tcmalloc
maxmemory-allocator jemalloc3. 客户端缓冲区配置
txt
# redis.conf
# 设置客户端输出缓冲区硬限制
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
# 设置客户端输入缓冲区限制
proto-max-bulk-len 512mb
# 设置客户端连接超时时间
timeout 3004. 复制缓冲区配置
txt
# redis.conf
# 设置复制积压缓冲区大小
repl-backlog-size 1mb
# 设置复制积压缓冲区过期时间
repl-backlog-ttl 36005. AOF 缓冲区配置
txt
# redis.conf
# 设置 AOF 重写缓冲区大小(由系统自动管理)
# 设置 AOF 写入策略
appendfsync everysec内存淘汰策略
1. 内存淘汰策略类型
Redis 支持多种内存淘汰策略,用于在内存达到上限时选择要删除的键:
- volatile-lru:从设置了过期时间的键中,使用 LRU(最近最少使用)算法删除
- allkeys-lru:从所有键中,使用 LRU 算法删除
- volatile-lfu:从设置了过期时间的键中,使用 LFU(最不经常使用)算法删除
- allkeys-lfu:从所有键中,使用 LFU 算法删除
- volatile-random:从设置了过期时间的键中,随机删除
- allkeys-random:从所有键中,随机删除
- volatile-ttl:从设置了过期时间的键中,优先删除剩余 TTL 最小的键
- noeviction:不删除键,返回错误(默认策略)
2. 淘汰策略配置
txt
# redis.conf
# 设置内存淘汰策略
maxmemory-policy allkeys-lru3. 淘汰策略选择
- volatile-lru:适合存在热点数据且大部分键设置了过期时间的场景
- allkeys-lru:适合存在明显热点数据的场景
- volatile-lfu:适合键访问频率变化较大的场景
- allkeys-lfu:适合键访问频率差异较大的场景
- volatile-random:适合没有明显热点数据的场景
- allkeys-random:适合数据访问均匀的场景
- volatile-ttl:适合需要根据 TTL 优先级删除键的场景
- noeviction:适合需要确保数据不丢失的场景
4. 淘汰策略监控
bash
# 查看淘汰键的数量
redis-cli info stats | grep evicted_keys
# 查看淘汰策略
redis-cli config get maxmemory-policy内存碎片管理
1. 内存碎片原因
- 频繁的键值对增删:导致内存分配和释放频繁
- 不同大小的键值对:导致内存分配的块大小不一致
- 内存分配器的特性:不同的内存分配器产生的内存碎片情况不同
2. 内存碎片率计算
bash
# 计算内存碎片率
mem_fragmentation_ratio = used_memory_rss / used_memory- 理想碎片率:1.0-1.5
- 高碎片率:>1.5
- 低碎片率:<1.0(可能存在内存交换)
3. 内存碎片处理
3.1 重启 Redis 实例
重启 Redis 实例是最直接的内存碎片处理方法,但会导致服务中断。
3.2 内存重分配
Redis 4.0+ 支持自动内存碎片整理:
txt
# redis.conf
# 启用自动内存碎片整理
activedefrag yes
# 设置内存碎片整理的触发条件
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100
active-defrag-cycle-min 25
active-defrag-cycle-max 75参数说明:
activedefrag:是否启用自动内存碎片整理active-defrag-ignore-bytes:内存碎片超过该值时才进行整理active-defrag-threshold-lower:内存碎片率超过该值时开始整理active-defrag-threshold-upper:内存碎片率超过该值时,尽最大努力整理active-defrag-cycle-min:内存碎片整理的最小 CPU 占用百分比active-defrag-cycle-max:内存碎片整理的最大 CPU 占用百分比
3.3 手动内存碎片整理
Redis 4.0+ 支持手动触发内存碎片整理:
bash
redis-cli memory defrag4. 内存碎片预防
- 合理规划键的生命周期:避免频繁的键值对增删
- 使用合适的数据结构:选择内存效率高的数据结构
- 合理设置内存分配器:不同的内存分配器产生的内存碎片情况不同
- 定期监控内存碎片率:及时发现和处理内存碎片问题
大键管理
1. 大键定义
大键是指占用内存较大的键,具体定义因业务场景而异,一般包括:
- 大字符串:单个字符串超过 10MB
- 大哈希:哈希表中的字段数量超过 10,000
- 大列表:列表中的元素数量超过 10,000
- 大集合:集合中的元素数量超过 10,000
- 大有序集合:有序集合中的元素数量超过 10,000
2. 大键危害
- 内存使用不均:导致部分内存块过大,影响内存分配
- 性能问题:大键的读写操作会阻塞 Redis 主线程
- 持久化问题:大键会导致 RDB 和 AOF 持久化时间过长
- 复制问题:大键会导致主从复制延迟增加
- 删除问题:删除大键会阻塞 Redis 主线程
3. 大键发现
3.1 使用 redis-cli --bigkeys 命令
bash
redis-cli --bigkeys该命令会扫描所有键,按数据类型统计最大的键。
3.2 使用 SCAN 命令结合 DEBUG OBJECT 命令
bash
#!/bin/bash
# 扫描所有键,找出大键
redis-cli scan 0 MATCH * COUNT 1000 | while read KEY; do
# 获取键的内存使用情况
MEMORY_USAGE=$(redis-cli memory usage $KEY)
if [ $MEMORY_USAGE -gt 10485760 ]; then # 10MB
echo "Big key found: $KEY, Memory usage: $MEMORY_USAGE bytes"
fi
done3.3 使用第三方工具
- redis-rdb-tools:分析 RDB 文件,找出大键
- redis-memory-analyzer:实时分析 Redis 内存使用情况
4. 大键处理
4.1 拆分大键
- 大哈希拆分:将大哈希拆分为多个小哈希
- 大列表拆分:将大列表拆分为多个小列表
- 大集合拆分:将大集合拆分为多个小集合
- 大有序集合拆分:将大有序集合拆分为多个小有序集合
4.2 使用异步删除
Redis 4.0+ 支持异步删除大键:
bash
# 使用 UNLINK 命令异步删除键
redis-cli unlink big_key
# 或使用配置参数启用异步删除
redis-cli config set lazyfree-lazy-server-del yes
redis-cli del big_key # 此时 DEL 命令会异步执行4.3 合理设置过期时间
为大键设置合理的过期时间,让 Redis 自动删除过期的大键:
bash
# 设置键的过期时间为 1 天
redis-cli expire big_key 864004.4 定期清理大键
定期清理不再使用的大键,避免占用过多内存。
内存监控和告警
1. 监控指标
- 内存使用量:
used_memory、used_memory_rss、used_memory_peak - 内存碎片率:
mem_fragmentation_ratio - 淘汰键数量:
evicted_keys - 客户端连接数:
connected_clients - 复制积压缓冲区使用情况:
repl_backlog_active、repl_backlog_size、repl_backlog_first_byte_offset、repl_backlog_histlen
2. 告警阈值设置
- 内存使用率:超过 80% 时告警
- 内存碎片率:超过 1.5 或低于 1.0 时告警
- 淘汰键数量:短时间内淘汰键数量急剧增加时告警
- 客户端连接数:接近
maxclients时告警
3. 监控工具
- Prometheus + Grafana:常用的监控组合,支持自定义仪表盘和告警
- Redis Exporter:用于采集 Redis 监控指标
- Datadog:提供 Redis 监控集成
- New Relic:提供 Redis 监控集成
- Zabbix:支持 Redis 监控模板
4. 告警方式
- 邮件告警:将告警发送到指定邮箱
- 短信告警:将告警发送到指定手机号
- 即时通讯工具告警:将告警发送到 Slack、Discord、企业微信、钉钉等即时通讯工具
- 监控平台告警:在监控平台上显示告警
常见问题(FAQ)
Q1: 如何选择合适的内存淘汰策略?
A1: 选择内存淘汰策略需要考虑业务场景:
- 存在明显热点数据:使用
allkeys-lru或allkeys-lfu - 大部分键设置了过期时间:使用
volatile-lru或volatile-lfu - 数据访问均匀:使用
allkeys-random - 需要根据 TTL 优先级删除:使用
volatile-ttl - 不允许数据丢失:使用
noeviction
Q2: 如何处理高内存碎片率问题?
A2: 处理高内存碎片率问题的方法:
- 启用自动内存碎片整理:Redis 4.0+ 支持自动内存碎片整理
- 手动触发内存碎片整理:使用
memory defrag命令 - 重启 Redis 实例:最直接的方法,但会导致服务中断
- 优化内存使用:减少频繁的键值对增删,使用合适的数据结构
Q3: 如何发现和处理大键?
A3: 发现和处理大键的步骤:
- 发现大键:使用
redis-cli --bigkeys、SCAN 命令结合 DEBUG OBJECT 命令或第三方工具 - 分析大键:确定大键的类型、大小和使用频率
- 处理大键:拆分大键、使用异步删除、合理设置过期时间或定期清理
Q4: 如何优化 Redis 内存使用?
A4: 优化 Redis 内存使用的方法:
- 使用合适的数据结构:选择内存效率高的数据结构
- 合理设置过期时间:让 Redis 自动删除过期数据
- 压缩数据:对于字符串类型数据,可以考虑压缩存储
- 拆分大键:将大键拆分为多个小键
- 合理配置内存淘汰策略:根据业务场景选择合适的淘汰策略
- 定期清理不再使用的数据:避免占用过多内存
Q5: 如何监控 Redis 内存使用?
A5: 监控 Redis 内存使用的方法:
- 使用 INFO memory 命令:获取内存使用的详细统计信息
- 使用 redis-cli --bigkeys 命令:发现大键
- 使用监控工具:如 Prometheus + Grafana、Datadog、New Relic 等
- 设置告警:当内存使用率超过阈值时触发告警
Q6: 如何处理 Redis 内存溢出问题?
A6: 处理 Redis 内存溢出问题的方法:
- 增加 Redis 内存:调整
maxmemory参数,增加 Redis 可用内存 - 优化内存使用:使用合适的数据结构,合理设置过期时间,拆分大键等
- 调整淘汰策略:选择合适的内存淘汰策略,及时删除不常用的数据
- 垂直扩展:升级 Redis 服务器的硬件配置
- 水平扩展:使用 Redis Cluster 或分片技术扩展 Redis 集群
