Redis系列之内存碎片

概述

在使用CacheCloud时看到一个碎片率的监控指标,于是有了此文。

简介

内存碎片率,memory fragmentation ratio,MFR,Redis的一个性能指标,其计算公式:MFR=used_memory_rss/used_memory

无论是通过redis-cli还是RDM工具,输入info或更具体的info memory命令,即可得到如下信息:

used_memory:15288560
used_memory_human:14.58M
used_memory_rss:14237696
used_memory_rss_human:13.58M
mem_fragmentation_ratio:0.93
mem_allocator:jemalloc-3.6.0

输出参数:

  1. used_memory
    已使用的内存大小,包括redis进程内部开销和cache的数据所占用的内存,单位byte;human表示可读数据,单位Mb,即除以2^20
  2. used_memory_rss
    rss,Resident Set Size,表示redis物理内存的大小,即向OS申请多少内存使用
  3. mem_fragmentation_ratio:
    1. 小于1时,表示发生swap,正在使用虚拟内存,即可用内存不够,虚拟内存其实就是硬盘,性能比内存低得多,应该增强机器的内存以提高性能
    2. 内存碎片率略高于1属于正常,一般超出1.5(待确认?)就说明redis的内存管理变差
    3. 远大于1时,表示分配的内存超过实际使用的内存;数值越大,碎片率越严重
  4. mem_allocator:
    指定编译时Redis使用的内存分配器:libc、jemalloc、tcmalloc,默认是jemalloc。jemalloc在64位系统中,将内存空间划分为小、大、巨大三个范围;每个范围内又划分许多小的内存块单位;存储数据的时候,会选择大小最合适的内存块进行存储。
    在这里插入图片描述

另外,当内存使用量(used_memory)很小的时候,这个值参考价值不大。所以,建议used_memory至少1G以上才考虑对内存碎片率进行监控。

碎片整理允许Redis压缩内存空间,从而回收内存。

原因

分析实际环境,因为该redis主要是存储频繁更新的数据,每次更新数据之前,redis会删除旧的数据,实际上,由于Redis释放了内存块,但内存分配器并没有返回内存给操作系统,这个内存分配器是在编译时指定的,可以是libc、jemalloc或者tcmalloc。used_memory_rss会越来越大,导致MFR越来越高。

当Redis中清理大量的Key之后原先Redis申请的内存(used_memory_rss)将继续持有而不会释放,此时查看内存信息将会看到存在大量的内存碎片。

redis产生内存碎片有两个原因,

  1. redis自身的内存分配器。
  2. 修改cache的值,且修改后的value与原来value的大小差异较大。

进程需要用内存的话,会先通过OS向device申请,然后才能够使用。一般进程在不需要使用的时候,会释放掉这部分内存并返回给device。但是redis作者可能为了更高的性能,所以在redis中实现了自己的内存分配器来管理内存,不会马上返还内存,不用每次都向OS申请了,从而实现高性能。

但是,在内存分配器的那张图片我们知道,redis的每个k-v对初始化的内存大小是最适合的,当这个value改变的并且原来内存大小不适用的时候,就需要重新分配内存了。(但是value存比原来小不知道会不会产生碎片)。重新分配之后,就会有一部分内存redis无法正常回收,一直占用着。

解决方法

  1. Redis 4 以前的版本,重启Redis服务器可以让额外产生的内存碎片失效并重新作为新内存来使用,使操作系统恢复高效的内存管理;
  2. Redis 4+ 版本,
  3. 修改内存分配器。Redis支持glibc’s malloc、jemalloc11、tcmalloc几种不同的内存分配器,每个分配器在内存分配和碎片上都有不同的实现。不建议普通管理员修改Redis默认内存分配器,因为这需要完全理解这几种内存分配器的差异,也要重新编译Redis。

Redis4版本之后开始支持内存碎片的清理,默认情况下自动清理碎片的参数是关闭的:config get activedefrag应该得到no的输出,开启:config set activedefrag yes,再次输入config get activedefrag验证输出是否为yes。

开启后,后台会启动进程,也可以手动清理:memory purge

查看:memory malloc-stats
注:此命令自版本可用。
TODO:输出解读。。

参数

相关参数配置说明

# Enabled active defragmentation
# 碎片整理总开关
# activedefrag yes

# Minimum amount of fragmentation waste to start active defrag
# 内存碎片达到多少的时候开启整理
active-defrag-ignore-bytes 100mb

# Minimum percentage of fragmentation to start active defrag
# 碎片率达到百分之多少开启整理
active-defrag-threshold-lower 10

# Maximum percentage of fragmentation at which we use maximum effort
# 碎片率小余多少百分比开启整理
active-defrag-threshold-upper 100

# Minimal effort for defrag in CPU percentage
active-defrag-cycle-min 25

# Maximal effort for defrag in CPU percentage
active-defrag-cycle-max 75

源码

  • 待补充

分配器

jemalloc

Redis 3.2.9 (整个3版本?)的默认分配器

tcmalloc

glibc’s malloc

即libc

参考

Redis 4.0 自动内存碎片整理(Active Defrag)源码分析
Inside of Jemalloc
Redis性能问题排查解决手册(七)
https://www.cnblogs.com/gjc592/p/12180024.html

posted @ 2020-07-09 23:41  johnny233  阅读(59)  评论(0编辑  收藏  举报  来源