Redis所有的数据都存在内存中,因此如何高效利用Redis内存非常重要。
1.1 内存使用统计
info memory可以获取内存的相关指标,主要关注以下几个指标:
used_memory: 分配的内存总量,内部存储所有数据的内存占用量。
used_memory_rss: 操作系统角度显示redis占用的物理内存总量。
mem_fragmentation_ratio: used_memory_rss/used_memory,表示内存碎片率。
当内存碎片率大于1,说明多出来的内存没有用于数据存储,如果相差很大,说明碎片率严重
当内存碎片率小于1,一般由于swap到硬盘导致,会导致Redis性能变差,需要特别关注。
1.2 内存消耗划分(自身内存+对象内存+缓冲内存+内存碎片)
自身内存:Redis自身内存消耗非常少,可以忽略不计。
对象内存:占用最大的一块,存储用户所有数据。可以简单理解为sizeof(keys)+sizeof(values)
缓冲内存:客户端缓冲(详见客户端那一篇),复制积压缓冲区(详见复制那一篇),AOF缓冲区(空间占用很小)
内存碎片:默认内存分配器采用jemalloc,可选的还有:glibc、tcmalloc。分配内存策略一般采用固定范围的内存块进行分配。正常的碎片率在1.03左右。可能导致高碎片的操作:频繁做更新操作,大量的过期键删除。常用解决方法:数据对齐,安全重启。
1.3 子进程内存消耗
主要指重写时fork的内存消耗。根据实际要预留一些内存防止溢出。设置vm.overcommit_memory=1允许内核可以分配所有的物理内存。关闭THP,防止copy-on-write期间内存过度消耗。
2.内存管理
2.1 内存上限
使用maxmemory参数限制最大可用内存(建议所有的redis服务器都要设置),对应的是used_memory统计的内存。实际消耗会更大,规划时务必预留一些内存。可以通过config set maxmemory来进行动态修改。
2.2 内存回收策略
删除过期的键对象:惰性删除和定时任务删除
内存使用达到maxmemoy上限时触发内存溢出控制策略,受maxmemory-policy参数控制(可以通过config set设置),策略有六种,默认noeviction(拒绝所有人写入,只响应读),其他策略上网看吧。
3.内存优化
3.1 redisObject对象
Redis存储的所有值对象在内部定义为redisObject的结构体。
type:4 ——对象类型
encoding:4 ——内部编码类型
lru:REDSIS_LRU_BITS ——LRU计时时钟
int refcount ——引用计数器
void *ptr——数据指针
3.2 缩减键值对象
降低内存的使用直接的方法就是缩减键值的长度
3.3 共享对象池
Redis内部维护[0-9999]的整数对象池。开发中在满足需求的前提下,尽量使用整数对象以节省内存。相同数据内存可以降低30%以上。
3.4 字符串优化
尽量减少字符串频繁修改操作如append、setrange,改为直接使用set
3.5 编码优化
使用ziplist压缩编码优化hash、list等结构,注重效率和空间的平衡
使用intset编码优化整数集合
使用ziplist编码和hash结构降低小对象链规模
题外话:innobackupex全量恢复的时候,最后一步--copy-back没有必要,直接把所有数据文件mv到mysql的data目录即可。这一章有关Redis编码的部分目前理解能力有限,就只能记个大概,遇到的时候再深入研究吧。
今天,和一个大佬(两个月就在北京有房)聊了几句,感受颇深。机会只留给有准备的人,对绝大多数人来说,你除了学习,真的没有任何机会。切记,人外有人,与君共勉。
参考资料:付磊、张益军.Redis开发与运维.北京:机械工业出版社,2017.02.
部分内容来自网络,如有侵权请联系作者删除。