18.Redis的内部碎片
对于Redis的使用过程中,可能存在的碎片问题,本章将会进行介绍
可以大致分为内存碎片的产生原因,如何解决内存碎片这两个部分
那么首先要说的就是关于内存碎片的产生原因,在这一部分也可以大致将其分为了获取内存的部分和使用过程中导致的部分
在Redis获取内存的过程中,可能因为内存分配器的分配策略导致实际获取的内存和理想的内存大小并不一致
Redis在实际使用过程中,可以使用libc jemalloc tcmalloc来分配内存,默认使用jemalloc,我们就说下jemalloc来说一下存在的内存
jemalloc的分配策略之一,就是按照一系列固定的大小划分内存空间,例如8字节,16字节,32字节,48字节,2KB 4KB等,当你申请的内存空间接近于某个固定值的时候,jemalloc就会给其分配相对应接近的内存空间,比如Redis申请一个20字节的空间保存数据,jemalloc就会分配32字节,这就导致了12字节的空闲空间,如果没有很好的利用的话,就会产生了内存碎片
然后是使用过程中的导致部分,Redis通常作为共用的缓存系统或者键值数据库对外提供服务,导致不同客户端请求的键值对大小可能不一致,故申请的内存空间也不一致,所以也会造成一定的内存碎片.在之后的删除操作,可会造成大小不一的内存空闲空间.
举个例子:
一开始,应用A B C D 分别保存了 3 1 2 4 字节的数据
D删除了1个字节,让1个字节空间空闲了,然后A将3字节变为了4字节,B被拷贝到了原本D的位置
后来C删除2字节,D删除了1字节,导致出现了两个内存碎片,分别为2字节和1字节
这样我们就知道了内存碎片的内外因素,之后就是第二部分,如何解决内存碎片
内存碎片的解决方案
首先要明确内存碎片的诊断方式
如何确定出现了内存碎片,Redis自身提供了INFO命令,来查询内存使用的详细信息
Redis提供了INFO命令,来查询内存使用的详细信息
获取的信息如下:
INFO memory
# Memory used_memory:1073741736 used_memory_human:1024.00M used_memory_rss:1997159792 used_memory_rss_human:1.86G … mem_fragmentation_ratio:1.86 |
这里有一个mem_fragmentataion_ratio的指标,表示的就是Redis当前的碎片率,其计算方式为
used_memory_rss和used_memory相除,也就是操作系统实际分配给Redis的物理内存空间和Redis实际保存数据的空间大小
mem_fragmentation_ratio = used_memory_rss/used_memory
对于这个mem_fragmentation_ratio就是我们判断是否需要优化内存碎片的主要根据
如果此指标大于1但小于1.5的话,说明在于正常范围
如果大于了 1.5,说明碎片率超过了50%,需要考虑使用一些措施了
那么如何清理内存碎片
简单的方法就是重启Redis实例,这样虽然可以减少内存碎片,但是这会带来数据持久化的问题,需要进行加载RDB或者AOF文件
后来Redis自身提供了一个gc的方式,利用了标记-整理的方式进行内存碎片的清除
就是将数据标记后重新整理,将原本不连续的内存空间变成连续的空间
使用其只需要将activedefrag配置项设置为yes
config set activedefrag yes
但是gc往往需要消耗CPU计算时间,这就导致阻塞主线程的情况存在,导致Redis的性能进一步降低
所以对于这个GC操作,Redis不仅提供了开启和关闭,还提供了一系列的限制参数,如下两个条件,满足两个就开始清理,如果有一个不满足就停止清理
active-defrag-ignore-bytes 100mb 内存碎片的字节数达到了100MB
active-defrag-threshold-lower 10 内存碎片空间占操作系统分配给Redis的总空间比例为10%
在清理过程中,为了减少占用的CPU比例,还设置了两个参数,避免造成过长时间的阻塞
分别是
active-defrag-cycle-min
active-defrag-cycle-max
分别说明了占用的CPU时间比例不能低于和高于一定时间,不然就停止清理
要根据实际的使用,来合理的设置这几个参数
本章我们总结一下,说了Redis的内存空间,说了内存碎片的产生可能性
其次就是info memory命令是一个好工具,可以查看碎片率的情况
利用碎片率阈值来确定是否需要进行碎片清理
自动清理在使用过程要注意设置其清理的界限,提高收益率
最后一个小问题
什么时候会出现mem_fragmentation_ratio小于1的情况呢?
首先说,是由于Swap机制导致的,这种情况下,访问已经被保存在硬盘的数据时候,会需要发生置换反应,导致降低Redis效率