大内存空间大小对Redis来说至关重要。内存越多,存储的数据越多,但有时明明空间很大,内存使用率却不是很理想,这就诡异了。
⼀、查看内存使用情况
Redis中查看内存相关信息在命令⾏输⼊【info memory】就可看到各种相关数据,咱汇总了一些常用参数,如下:
used_memory:已经使用的内存大⼩。
used_memory_rss:redis物理内存的大⼩。
mem_fragmentation_ratio:内存碎片率。
内存碎片率这个名词需注意下,它用来表示当前内存使用情况,计算方式如下:
内存碎片率,一般保持在1~1.5之间是最合理的。
⼆、内存碎片是啥?
定义:由于一块连续空闲的空间比所要申请的空间⼩,致这块空间不可用,对内存整体来说就是内存碎片。
举个栗子:
假设有100MB的连续空闲内存空间,每次都会从中申请一块30MB的内存。当申请3次后,这块内存就只剩下了10MB的空间,第4次申请的时候就会失败。如果没其它的空间释放且每次申请的空间都比10MB⼤,那剩下的空间对整块内存来说就是内存碎片。
三、产生内存碎片原因
Redis中,常用操作是写⼊、修改、删除数据,执行后都会产生一定程度的内存碎⽚。
1、写入数据
Redis中,分配内存是根据固定大⼩来划分内存空间的,为减少分配次数,Redis会根据申请的内存最接近的固定值分配相应大⼩空间。
举个栗子:
假如Redis按照8字节、16字节、32字节、48字节等来分配内存。当想存储一个18字节的数据,此时Redis就会分配32字节(因为32是与18最接近的固定值),如果这时候再写入的数据需要的内存空间在14个字节内,Redis就无需再进行分配。
像不同的箱⼦,为装东西,需要找⼀个体积最接近的箱子来,装进去后,发现还有空间可以放⼀些小东⻄,就无需再找箱子了。
但这种分配空间方式会带来一定程度的内存碎片。我们可把固定大⼩的划分空间看成不同体积的箱⼦,每种箱子空间有不同程度剩余,此剩余空间就是内存碎⽚。
2、修改数据
键值对修改时,会变大或变⼩,对应会占用额外空间或释放不用的空间。
上图中,A、B、C分别占用3、2、4个字节,将A从3字节改为2字节时,就会有1个字节的空间空了出来,就出现了1个字节碎片。
假如将A从3字节改为4字节,为保持A空间连续性,操作系统把B拷贝到别的空间,又出现了1个字节碎⽚。
3、删除数据
下图中,删除B释放2字节空间,对整个内存空间来说就产生2字节碎⽚。
四、解决内存碎⽚
以上述箱子例子来看内存碎片的危害。
如果要把这些箱子都装车运走,每个箱子里都有空出来的空间(内存碎⽚),那么运行一次的效率及性价比是不是会很低。
同样,在Redis中,由于大量的碎片存在,会导致实际利用率变低,解决这个问题有两种方案,来具体看下。
1、推倒重来
这种方式很简单,直接推倒重来。就是直接重启Redis,对内存来说一断电全世界就清净了,但这种暴力省事的方式有很多隐患。
生产环境中要这么来得提前烧香,保佑不出问题,但要是没进行过持久化,就别烧了,没啥用。
如果有持久化的话,那么恢复时长还得取决持久化文件的大⼩,这个阶段无法对外提供服务。心塞不?
2、空间置换
高版本的Redis提供内存碎片清理的方式,一言蔽之就是空间置换。
试想一下,我们的目的是为了消除内存碎片,那把已使用的内存数据重新整理到一起不就完了,让不连续空间变连续,剩下的空间继续分配。
如下:
理论简单,但理论到实践中还隔着性能损耗。
进行多次数据拷贝过程中,单线程的Redis只能干等着,无法响应客户端的请求,只能干瞪眼,性能太受影响。
别急,再来看下缓解的策略。
Redis中有专⻔的参数用来设置进行自动清理内存碎⽚:activedefrag yes。
此命令用来启动清理功能,这还不够,Redis还需要其他条件限制才能进行清理。
下面参数都是满足任一条件后就进行清理:
active-defrag-ignore-bytes 100mb:达到100MB。
active-defrag-threshold-lower 10:碎片超过10%。
active-defrag-threshold-upper 100:超过100%,尽最大清理。
处理过程中,为避免影响正常请求,同时保证性能,Redis提供了监控CPU占用比例的参数,满足以下条件时才会保证清理正常开展:
active-defrag-cycle-min 5:清理内存碎片占用CPU时间的比例不低于此值,保证清理能正常开展。
active-defrag-cycle-max 75:清理内存碎片占⽤CPU时间的⽐例不高于此值。超过则停止,避免在清理时,大量内存拷贝阻塞Redis,致其它请求延迟。
五、总结
查看内存使用情况
(1)命令⾏执⾏info memory可看Redis内存相关信息,根据内存碎片率可以在一定时机内进行碎片清理。
导致内存碎片的原因
(1)写数据时,Redis为减少分配次数,分配内存根据固定大⼩来划分内存空间,修改数据释放或占用额外内存空间,删除数据释放空间,以上操作会产生不同程度的内存碎片。
解决内存碎片问题
(1)重启Redis进行处理,如无持久化会导致事故,在持久化情况下,恢复速度取决于文件大⼩。
(1)通过空间置换方式,也就是将已使用的内存数据重新整理到一起。
以上为个人认知,如有侵权,请联系删除。