高效利用Redis内存需要理解内存消耗在哪里,然后在管理内存,优化内存。
内存消耗分析、管理内存的原理和方法、内存优化技巧
8.1 内存消耗
想理解Redis内存,首先要知道Redis内存消耗在哪些方面。可以通过参数调整和合理使用来规避内存浪费。内存消耗可以分为进程自身消耗和子进程消耗
8.1.1 内存使用统计
1 通过执行info memory获取内存相关指标
需要重点关注的指标有:used_memory_rss和used_memory以及它们的比值mem_fragmentation_radio
当mem_fragmentation_radio>1时,说明used_memory_rss-used_memory多出的部分内存没有用于数据存储,而是被内存碎片所消耗,如果两者相差很大,说明碎片率严重
当mem_fragmentation_radio<1时,操作系统把Redis内存交换(Swap)到硬盘导致。
8.1.2 内存消耗划分
自身内存+对象内存+缓冲内存+内存碎片
1 对象内存
占用内存最大的一块,存储用户所有数据。内存消耗=sizeof(keys)+sizeof(values)
注意:避免使用过长的键和合理预估并监控value对象占用情况,避免内存溢出
2 缓冲内存
客户端缓冲、复制积压缓冲区、AOF缓冲区
客户端缓冲:所有接入到Redis服务器TCP连接的输入输出缓冲。
普通客户端:除了复制和订阅的客户端之外的所有连接?不明白
从客户端:主结点为每个结点单独建立一条连接用于命令复制
订阅客户端:当使用发布订阅功能时,连接客户端使用单独的输出缓冲区
输入输出缓冲区在大流量的场景中容易失控,造成Redis内存的不稳定,需要重点监控
复制积压缓冲区
可重用的固定大小缓冲区用于实现部分复制功能
AOF缓冲区
这部分空间用于在Redis重写期间保存最近写入命令
3 内存碎片
内存分配器采用jemalloc,有可选的。内存分配器为了更好的管理和重复利用内存,分配内存策略一般采用固定范围的内存块进行分配
出现高内存碎片问题解决方式:
数据对齐和安全重启
8.1.3 子进程内存消耗
Redis产生的子进程并不需要消耗1倍的父进程内存,实际消耗根据期间写入命令量决定,但是依然要预出一些内存防止溢出
需要设置sysctl vm.overcommit_memory=1允许内核可以分配所有的物理内存,防止Redis进程执行fork时因系统剩余内存不足而失败
排查当前系统是否支持并开启THP,如果开启建议关闭,防止Copy-on-write期间内存过度消耗
8.2 内存管理
通过控制内存上限和回收策略实现内存管理
8.2.1 设置内存上限
限制内存使用的目的:
用于缓存场景,当超出内存上限maxmemory时使用LRU等删除策略释放空间
防止所用内存超过服务器物理内存
8.2.2 动态调整内存上限
config set maxmemory进行动态修改,即修改最大可用内存。
Redis默认无限使用服务器内存,为防止极端情况,建议所有的Redis进程都要设置maxmemory,在保证物理内存可用的情况下,系统中所有Redis实例可以调整maxmemory参数来达到自由伸缩内存的目的
8.2.3 内存回收策略
1 删除过期键对象
惰性删除和定时任务删除
2 内存溢出控制策略
建议线上内存工作在maxmemory>used_memory状态下,避免频繁内存回收开销
8.3 内存优化
8.3.1 redisObject对象
高并发写入场景中,在条件允许的情况下,建议字符串长度控制在39字节以内,减少创建redisObject内存分配次数,从而提高性能
8.3.2 缩减键值对象
减少key长度和减少value长度
8.3.3 共享对象池
8.3.4 字符串优化
所有的键都是字符串类型。
1 字符串结构
内部简单实现动态字符串
2 预分配机制
3 字符串重构
不一定把每份数据作为字符串整体存储,
8.3.5 编码优化
1 了解编码
所谓编码,就是具体使用哪种底层数据结构来实现 object encoding 获取编码类型
多种编码类型:是想通过不同编码实现效率和空间的平衡
2 控制编码类型
输入写入的时候自动完成,不可逆
3 ziplist编码
4 inset编码
集合set类型编码的一种,内部表现为存储有序、不重复的整数集。
1 encoding:整数表示类型,根据集合内最长整数值确定类型,整数类型划分为三种:int-16、int-32、int-64
2 length 表示集合元素个数
3 contents 整数数组,按从小到大顺序保存
intset保存的整数类型根据长度划分,保存的整数类型超出当前类型时,将自动触发升级不回退,升级操作将会导致重新申请内存空间,把原有数据拷贝到新数组。
8.3.6 控制键的数量
对于存储相同数据内容利用Redis的数据结构降低外层键的数量,可以节省大量内存。
hash结构降低键数量分析
根据键规模在客户端通过分组映射到一组hash对象中
hash的field可用于记录原始key字符串,方便哈希查找
hash的value保存原始值对象,确保不要超过hash-max-ziplist-value限制
8.4 本章重点回顾