内存碎片
内因:操作系统的内存分配机制
- Redis 可以使用 libc、jemalloc、tcmalloc 多种内存分配器来分配内存,默认使用jemalloc。
- jemalloc 的分配策略之一,是按照一系列固定的大小划分内存空间, jemalloc分配8字节,16字节等等,可能造成碎片。
外因:键值对大小不一样和删改操作
如果判断
INFO 命令
mem_fragmentation_ratio = used_memory_rss(操作系统实际分配给 Redis 的物理内存空间)/ used_memory(Redis 为了保存数据实际申请使用的空间)
- mem_fragmentation_ratio 大于 1 但小于 1.5: 合理的,
- mem_fragmentation_ratio 大于 1.5 :需要采取措施。
- mem_fragmentation_ratio 小于 1,没有足够的内存了,redis一部分内存数据会被换到swap中
如何清理内存碎片?
- 重启实例(数据没实例化的话,容易丢失)
- 自动碎片清理,
config set activedefrag yes
,清理需要满足下面的两个条件- active-defrag-ignore-bytes 100mb:表示内存碎片的字节数达到 100MB 时,开始清理;
- active-defrag-threshold-lower 10:表示内存碎片空间占操作系统分配给 Redis 的总空间比例达到 10% 时,开始清理。
- 自动内存碎片清理功能在执行时,还会监控清理操作占用的 CPU 时间
- active-defrag-cycle-min 25: 表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展;
- active-defrag-cycle-max 75:表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致响应延迟升高。
缓冲区溢出的方案
客户端输入输出缓冲区
输入缓冲区溢出的情况
- 写入big key(避免大key写入)
- 服务段处理请求慢(避免主线程阻塞)
CLIENT LIST
命令可以看到
- Redis客户端最多暂存1GB大小的数据
输出缓冲区溢出的情况
- 服务器端返回big key的大量结果。
- 执行monitor命令
- 用来检测redis执行。
- 缓冲区大小不合理
client-output-buffer-limit 配置项,来设置缓冲区的大小
- 设置缓冲区大小的上限阈值;
- 设置输出缓冲区持续写入数据的数量上限阈值,和持续写入数据的时间的上限阈值。
客户端分为普通客户端和订阅客户端。
- 普通客户端:
client-output-buffer-limit normal(代表的是普通客户端) 0(缓冲区大小限制) 0(缓冲区持续写入量限制) 0(持续写入时间限制)
- 订阅客户端:
client-output-buffer-limit pubsub(订阅客户端) 8mb(输出缓冲区的大小上限) 2mb 60 (连续 60 秒内对输出缓冲区的写入量超过 2MB 的话,服务器端也会关闭客户端连接)
主从集群中的缓冲区
复制缓冲区的溢出问题
-
在全量复制过程中,主节点在向从节点传输 RDB 文件的同时,会继续接收客户端发送的写命令请求。这些写命令就会先保存在复制缓冲区中,等 RDB 文件传输完成后,再发送给从节点去执行。主节点上会为每个从节点都维护一个复制缓冲区,来保证主从节点间的数据同步。
-
那如何避免复制缓冲区发生溢出
- 控制主节点保存的数据量大小(主节点的数据量控制在 2~4GB)
- 使用
client-output-buffer-limit
配置项,来设置合理的复制缓冲区大小。 - 控制从节点的数量
-
主节点的设置
config set client-output-buffer-limit slave(针对复制缓冲区的) 512mb(将缓冲区大小的上限) 128mb 60(如果连续 60 秒内的写入量超过 128MB 的话,也 会触发缓冲区溢出)
复制积压缓冲区的溢出问题
- 增量复制时使用的缓冲区,这个缓冲区称为复制积压缓冲区
- 主节点在把接收到的写命令同步给从节点时,同时会把这些写命令写入复制积压缓冲区。一旦从节点发生网络闪断,再次和主节点恢复连接后,从节点就会从复制积压缓冲区中,读取断连期间主节点接收到的写命令,进而进行增量同步
- 复制积压缓冲区是一个大小有限的环形缓冲区。
- 如果写满,从节点还没有同步这些旧命令数据,就会造成主从节点间重新开始执行全量复制。
- 以调整复制积压缓冲区的大小,也就是设置
repl_backlog_size
这个参数的值