内存消耗
Redis进程内消耗包括:自身内存 + 对象内存 + 缓冲内存 + 内存碎片
其中自身内存消耗非常小,占3M左右,主要是其它3种内存
内存消耗划分
- 对象内存是Redis内存占用最大一块
- 缓冲内存包括 客户端缓冲、复制积压缓冲区、AOF缓冲区
- 内存碎片:频繁更新操作、大量过期键删除会造成内存碎片,通过数据对齐和安全重启可以降低碎片
子进程内存消耗
- Redis产生的子进程并不需要消耗1倍父进程内存,实际消耗根据写入命令量决定
- 需要设置允许内核可以分配所有的物理内存,防止Redis进程执行fork时因系统剩余内存不足而失败
- 排查当前系统是否支持并开启THP,建议关闭,防止copy-on-write期间内存过度消耗
内存管理
设置内存上限
- Redis使用 maxmemory 参数限制最大可用内存
- 因为内存碎片率的存在,实际使用可能要大一些,要防止内存溢出
- 该设置用于缓存场景,超过后使用LRU等删除策略释放空间
- 该设置防止所用内存超过服务器物理内存
动态调整内存上限
- 执行
config set maxmemory
命令进行动态修改 - 通过动态修改maxmemory,可以实现当前服务器下动态伸缩Redis内存的目的
内存回收策略
- 删除过期对象:惰性删除 / 定时任务删除
- 内存溢出控制策略:noeviction(默认)、volatile-lru(LRU删除超时键)、allkeys-lru(LRU删除键)、allkeys-random(随机删除所有键)、volatile-random(随机删除过期键)、volatile-ttl(删除最近将要过期键)
内存优化
redisObject 对象
- 同一个对象采用不同的编码实现对内存占用有明显差异
- 可以使用
scan
+object idletime
命令批量查询长时间未访问键,清理以降低内存 - 通过对象引用次数回收内存,为0时可以安全回收当前对象
- 建议字符串长度控制在39字节以内,减少redisObject内存分配
缩减键值对象
- key长度:完整描述业务的情况下,键值越短越好
- value长度:把业务对象序列化成二进制数组放入Redis,另外避免无效数据
共享对象池
- 尽量使用整数对象以节省内存,因为Redis内部维护了一个整数对象池
- 共享对象池与maxmemory+LRU冲突
- ziplist编码的值对象,无法使用共享对象池
字符串优化
- 字符串采用预分配方式防止修改操作需要不断重分配内存和拷贝,造成内存浪费
- 尽量减少字符串频繁修改操作,改为直接用set修改字符串,降低预分配内存浪费和内存碎片化
- 字符串重构:json数据可以使用hash结构,可以部分修改
编码优化
- 使用
config set
命令设置编码相关参数满足使用压缩编码的条件 - 性能要求较高的场景使用ziplist,长度不要超过1000,每个元素大小控制在512字节内
- 使用intset编码的集合时,保持整数范围一致,防止个别大数触发集合升级,产生内存浪费
控制键的数量
- 利用hash结构降低键的数量
- 同样数据使用ziplist编码的hash比string类型的节约内存
- hash-ziplist类型比string写入耗时,但随着value空间减少,耗时降低
- ziplist长度需要控制在1000以内,长列表会导致CPU消耗严重
- hash重构后所有键无法使用超时和LRU淘汰机制自动删除
- 对于大对象(1KB),使用hash-ziplist结构控制反而得不偿失
- 对于大量小对象的存储场景,非常适合使用hash-ziplist来控制键来降低内存