前言
- Redis 是基于内存的 key-value 数据库,内存的大小是有限制的
- 在生产环境中,偶尔会遇到 Redis 服务器内存不够的情况,那对于这种情况 Redis 的内存是如何回收处理的呢?如果内存满了,Redis 会怎么办呢
一、查看 Redis 内存使用
#使用 192.168.126.15:6379 连接本机上的 Redis 数据库
[root@localhost ~]# redis-cli -h 192.168.126.15 -p 6379
192.168.126.15:6379> INFO memory #查看内存使用情况
# Memory
used_memory:853728 #由 Redis 分配器分配的内存总量,包含了 redis 进程内部的开销和数据占用的内存,以字节(byte)为单位
used_memory_human:833.72K #已更直观的单位展示分配的内存总量
used_memory_rss:16302080 #向操作系统申请的内存大小,与 top 与 ps 等命令的输出一致
used_memory_rss_human:15.55M #已更直观的单位展示向操作系统申请的内存大小
used_memory_peak:853728 #redis 的内存消耗峰值(以字节为单位)
used_memory_peak_human:833.72K #以更直观的格式返回 redis 的内存消耗峰值
used_memory_peak_perc:100.00% #使用内存达到峰值内存的百分比,即(used_memory / used_memory_peak) *100%
used_memory_overhead:841390 #Redis 为了维护数据集的内部机制所需的内存开销,包括所有客户端输出缓冲区、查询缓冲区、AOF 重写缓冲区和主从复制的 backlog
used_memory_startup:791416 #Redis 服务器启动时消耗的内存
used_memory_dataset:12338 #数据占用的内存大小,即 used_memory - sed_memory_overhead
used_memory_dataset_perc:19.80% #数据占用的内存大小的百分比,100%*(used_memory_dataset/(used_memory - used_memory_startup))
allocator_allocated:1304352
allocator_active:1634304
allocator_resident:11395072
total_system_memory:3958075392 #整个系统内存
total_system_memory_human:3.69G #以更直观的格式显示整个系统内存
used_memory_lua:37888 #Lua 脚本存储占用的内存
used_memory_lua_human:37.00K #以更直观的格式显示 Lua 脚本存储占用的内存
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0 #Redis 实例的最大内存配置
maxmemory_human:0B #以更直观的格式显示 Redis 实例的最大内存配置
maxmemory_policy:noeviction #当达到 maxmemory 时的淘汰策略
allocator_frag_ratio:1.25
allocator_frag_bytes:329952
allocator_rss_ratio:6.97
allocator_rss_bytes:9760768
rss_overhead_ratio:1.43
rss_overhead_bytes:4907008
mem_fragmentation_ratio:20.06 #碎片率&#xff0c;used_memory_rss/ used_memory&#xff0c;>1表示有碎片&#xff0c;<1表示部分Redis的内存被系统交换到硬盘&#xff08;此时Redis性能变差&#xff09;
mem_fragmentation_bytes:15489376
mem_not_counted_for_evict:96
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:49694
mem_aof_buffer:96
mem_allocator:jemalloc-5.1.0 #内存分配器
active_defrag_running:0 #表示没有活动的 defrag 任务正在运行&#xff0c;1 表示有活动的 defrag 任务正在运行&#xff08;defrag:表示内存碎片整理&#xff09;
lazyfree_pending_objects:0 #0表示不存在延迟释放的挂起对象
二、内存碎片率的计算
- 由操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存值 used_memory 计算得出
used_memory_rss&#xff1a;是Redis向操作系统申请的内存
used_memory&#xff1a;是Redis中的数据占用的内存
mem_fragmentation_ratio&#xff1a;内存碎片率mem_fragmentation_ratio &#61; used_memory_rss / used_memory
三、内存碎片的产生
内存碎片是由操作系统低效的分配/回收物理内存导致的&#xff08;不连续的物理内存分配&#xff09;&#xff1a;
- Redis 内部有自己的内存管理器&#xff0c;为了提高内存使用的效率&#xff0c;来对内存的申请和释放进行管理
- Redis 中的值删除的时候&#xff0c;并没有把内存直接释放&#xff0c;交还给操作系统&#xff0c;而是交给了 Redis 内部有内存管理器
- Redis 中申请内存的时候&#xff0c;也是先看自己的内存管理器中是否有足够的内存可用
- Redis 的这种机制&#xff0c;提高了内存的使用率&#xff0c;但是会使 Redis 中有部分自己没在用&#xff0c;却不释放的内存&#xff0c;导致了内存碎片的发生
三、内存碎片率的意义
跟踪内存碎片率对理解 Redis 实例的资源性能是非常重要的&#xff1a;
- 内存碎片率稍大于 1 是合理的&#xff0c;这个值表示内存碎片率比较低
- 内存碎片率超过 1.5&#xff0c;说明 Redis 消耗了实际需要物理内存的 150%&#xff0c;其中 50% 是内存碎片率&#xff0c;需要考虑是否要进行内存碎片清理&#xff0c;要引起重视
- 内存碎片率低于 1 的&#xff0c;说明 Redis 内存分配超出了物理内存&#xff0c;则操作系统正在进行内存交换&#xff0c;也就是说&#xff0c;开始使用硬盘了&#xff1b;需要增加可用物理内存&#xff08;扩容内存&#xff09;或减少 Redis 的内存占用
四、如何解决内存碎片率过大的现象
1.低于 4.0版本的 Redis
shutdown save
#在redis-cli 工具上输入&#xff0c;随后重启 Redis 服务器
#Redis 服务器重启后&#xff0c;Redis 会将没用的内存归还给操作系统&#xff0c;碎片率会降下来
2.高于 4.0版本的 Redis
#Redis 4.0版本开始&#xff0c;可以在不重启的情况下&#xff0c;线上整理内存碎片CONFIG SET activedefrag yes
#内存自动清理memory purge
#手动直接清理
INFO memory
#再次查看
五、内存使用率
- Redis 实例的内存使用率超过可用最大内存&#xff0c;操作系统就将开始进行内存与 swap 空间交换
- 避免内存交换发生的方法&#xff1a;
- 针对缓存数据大小选择安装 Redis 实例&#xff08;对于每一个 key&#xff0c;将使用更少的内存&#xff0c;即指针占用的字节数更少&#xff09;
- 尽可能的使用 Hash 数据结构存储&#xff08;Redis 在存储小于 100 个字段的 Hash 结构上&#xff0c;其存储效率非常高&#xff09;
- 设置 key 的过期时间&#xff08;减少 key 的数量&#xff09;
六、内回收 key&#xff08;内存驱逐策略&#xff09;
- 保证合理分配 redis 有限的内存资源
- 当达到配置文件最大内存限制的时候&#xff0c;需选择一种 key 的回收策略&#xff0c;即 Redis 有几种策略来处理这种情况&#xff1a;默认情况下回收策略是禁止删除
- 在配置文件中修改 maxmemory-policy 属性值&#xff08;直接修改对应部分即可&#xff09;&#xff1a;
vim /etc/redis/6379.conf
#598行
maxmemory-policy noeviction
#noenviction&#xff08;默认策略&#xff09;&#xff1a;禁止淘汰数据&#xff0c;对于写请求不再提供服务&#xff0c;直接返回错误&#xff08;DEL请求和部分特殊请求除外&#xff09;
#volatile-lru&#xff1a;从设置了过期时间的 key 中使用 LRU 算法进行淘汰
#volatile-ttl&#xff1a;在设置了过期时间的 key中&#xff0c;根据 key 的过期时间进行淘汰&#xff0c;越早过期的越优先被淘汰
#volatile-random&#xff1a;从设置了过期时间的 key 中随机淘汰
#allkeys-lru&#xff1a;从所有 key 中使用 LRU 算法进行淘汰
#allkeys-random&#xff1a;从数据集合中任意选择数据淘汰
- 驱逐策略如何生效&#xff1a;
- 当 Redis 收到一条会添加数据的命令
- Redis 检查内存使用情况&#xff0c;是否超过最大内存限制
- 超过则执行内存驱逐策略&#xff0c;然后执行命令
tips:如果某个命令大量使用内存&#xff0c;则占用内存可能会超过最大内存限制