第8章 理解内存
2018-05-25 本文已影响16人
leon4ever
理解Redis内存消耗,管理和优化。
1. 内存消耗
1.1 内存使用统计
通过info memory
命令获取内存相关指标,重点指标:
used_memory_rss //操作系统角度Redis进程占用的物理内存总量
used_memory //Redis内部存储的所有数据内存占用量
mem_fragmentation_ratio //内存碎片率 >1时说明多出的内存被内存碎片消耗,<1时则要注意操作系统swap到硬盘
1.2 内存消耗划分
Redis内存消耗划分.jpg- 对象内存:存储用户所有key-value数据
- 缓冲内存:客户端缓冲,复制积压缓冲区,AOF缓冲区
- 内存碎片:默认内存分配器:jemalloc
1.3 子进程内存消耗
- Redis产生的子进程并不需要1倍的父进程内存(copy-on-write),实际消耗根据写入命令量决定
- 需要设置
sysctl vm.overcommit_memory=1
允许内核可以分配所有物理内存,放置fork失败 - 排查当前系统是否开启THP,建议关闭,防止内存过度消耗
2. 内存管理
2.1 设置内存上限
- 用于缓存场景,超出上限时使用LRU释放空间
- 防止所用内存超过服务器物理内存
2.2 动态调整内存上限
config set maxmemory
动态修改内存,伸缩配置
2.3 内存回收策略
- 删除到达过期时间的键对象:惰性删除(客户端读取时检查删除)/定时任务删除
- 内存溢出控制策略:
- noeviction:默认,拒绝写入
- volatile-lru:LRU删除超时键
- allkeys-lru:LRU删除所有键
- allkeys-random:随机删除所有键
- volatile-random:随机删除过期键
- volatile-ttl:删除最近将要过期数据
注意:频繁执行回收内存成本很高,如果有从节点会同步,导致写放大
3. 内存优化
3.1 redisObject对象
redisObject内部结构.jpg- type:数据类型
- encoding:内部编码类型
- lru:最后一次被访问的时间
- refcount字段:记录当前对象被引用的次数
- *ptr字段:与对象的数据内容相关
3.2 缩减键值对象
降低Redis内存使用最直接的方法:缩减key和value的长度
选择高效的序列化工具
3.3 共享对象池
共享对象池是指Redis内部维护[0-9999]整数对象池。创建大量的整数类型redisObject存在内存开销。
使用共享对象池,相同的数据内存使用降低30%以上。
3.4 字符串优化
Redis有自己内部的动态字符串:
字符串结构体SDS.jpg
由于预分配机制,同样的数据追加后内存消耗非常严重。(追加后预分配一倍容量)
字符串重构:对json这种,可以使用hash这样的二级结构来饥饿省内存,支持字段的部分读取修改
3.5 编码优化
不同编码实现效率和空间的平衡
编码类型转换过程不可逆,只能从小内存编码向大内存编码转换。
3.6 控制键的数量
hash结构降低键数量分析
- 根据键规模在客户端通过分组映射到一组hash对象中
- hash的field可用于记录原始key字符串
- hash的value保存原始值结构
hash键和field键的设计:
- 键的离散度高时,按照字符串位截取
- 键离散度低,用哈希算法打散键,哈希field存储键的原始值
- 尽量减少hash键和field的长度,如使用部分键内容