Redis内存管理
  PBFgHg39AoKR 2023年11月02日 59 0

内存使用统计

我们可以通过执行info memory命令获取内存的相关指标

test.redis.cn:6379> info memory
# Memory
used_memory:74226360          //redis分配器分配的内存总量,也就是内部存储的所有数据内存占用量
used_memory_human:70.79M      //以可读格的格式返回used_memory
used_memory_rss:48910336      //从操作系统的角度显示Redis进程占用的物理内存总量
used_memory_rss_human:46.64M  
used_memory_peak:180955248    //内存使用的最大值,表示used_memory的峰值
used_memory_peak_human:172.57M  //以可读方式返回used_memory_peak 
used_memory_lua:48128       //Lua引擎锁消耗的内存大小
mem_fragmentation_ratio:0.66      //   used_memory_rss/used_memory的比值,表示内存碎片率
mem_allocator:jemalloc-5.1.0   //redis所使用的内存分配器,默认jemalloc

如果我们做了服务的监控,重点关注内存使用和redis的碎片率, 当mem_fragmentation_ratio > 1 时,说明used_memory_rss - used_memory 多出来的部分内存并没有用于数据存储,而是被内存碎片所消耗,如果两者差距很大,说明碎片严重。 当mem_fragmentation_ratio < 1 时,这种情况一般出现在操作系统吧redis内存交换(swap)到硬盘导致,出现这种情况要格外关注,由于硬盘速度远远慢于内存,redis性能会变得很差,设置僵死。

内存消耗

redis内存消耗主要有三部分组成:对象内存+缓冲内存+自身内存+内存碎片

对象内存

对象内存是redis内存占用最大的一块,存储着用户所有数据,redis的数据类型包括五种:字符串、哈希、集合、有序集合、列表,数据都采用key-value数据类型,应当避免使用过长的key,键的最大长度是512MB。这是一个非常大的长度,实际应用中的键通常会远小于这个长度。使用过长的键会增加内存的使用和网络传输的开销,所以在设计键的时候,通常会尽量保持键的长度尽可能的短,同时又能够清晰地表达键所代表的意义。

缓冲内存

缓冲内存主要包括:客户端缓冲、复制积压缓冲区、AOF缓冲区 客户端缓冲是指所有连接到redis服务器TCP连接的输入输出缓冲,输入输出无法控制,最大空间为1G,如果超过将断开连接。

内存碎片

redis默认内存分配器采用jemalloc,可选的分配器还有:glibc、tcmalloc。内存分配器为更好的管理和重复利用内存,分配内存策略一般采用固定范围的内存块进行分配。 jemalloc是Redis默认使用的内存分配器,它在内存管理上有很多优化,包括避免内存碎片化,提高内存利用率等。

jemalloc的内存空间划分主要包括以下几个部分:

  1. Tiny runs:这部分内存用于分配小于或等于512字节的内存块。这些内存块在jemalloc中被称为tiny runs。

  2. Small runs:这部分内存用于分配大于512字节小于等于32768字节(32KB)的内存块。这些内存块在jemalloc中被称为small runs。

  3. Large runs:这部分内存用于分配大于32768字节的内存块。这些内存块在jemalloc中被称为large runs。

  4. Huge runs:这部分内存用于分配大于1页的内存块。在jemalloc中,一页的大小通常为4KB,但这个值可能会因系统而异。这些内存块在jemalloc中被称为huge runs。

这种内存划分策略让jemalloc能够高效地分配和回收内存,减少内存碎片,提高内存利用率。另外,jemalloc还使用了其他一些技术来进一步优化内存管理,例如线程缓存、大小类别等。

子进程内存消耗

子进程内存消耗主要指执行AOF/RDB重写时redis创建的子进程内存消耗,redis执行fork操作产生的子进程内存占用量对外表现为与父进程相同,理论上需要一倍的物理内存来完成重写操作。但Linux具有写时复制技术(copy-on-write),父子进程会共享相同的物理内存页,当父进程处理写请求时会对需要修改的页夫指出一份副本完成写操作,而子进程依然读取fork时整个父进程的内存快照。

RDB重写时消耗的内存日志:

17515:C 28 Dec 12:53:23.091 * RDB: 69 MB of memory used by copy-on-write 27999:M 28 Dec 12:53:23.310 * Background saving terminated with success

内存上限

redis可以使用maxmomory参数来限制可用内存,限制主要目的是防止redis内存使用超过服务器物理内存(需要给操作系统预留内存),缓存场景,当内存上限maxmemory时使用过期删除策略,释放内存。 maxmemory限制的是redis实际使用的内存量,也就是used_memory统计项对应的内存,由于内存碎片率的存在,实际消耗的内存可能会比maxmemory设置的更大实际使用时要小心这部分内存溢出。 通过命令可以设置redis实例内存大小。

172.21.108.20:6399> config set  maxmemory 1G
OK
172.21.108.20:6399> config get maxmemory
1) "maxmemory"
2) "1000000000"

内存回收

redis内存回收机制主要体现在,删除过期时间的key和内存使用达到maxmemory上限时触发内存溢出控制策略

删除过期key

redis所有的key都可以设置过期时间,内部保存在过期字典中,由于进程内保存大量的key,维护每个键精准的过期删除机制会导致消耗大力选哪个的CPU,对于单线程的redis来说成本很高,因此redis采用惰性删除和定时任务删除机制实现过期键的内存回收。 惰性删除:用于当客户端读取带有超时属性的key时,如果已经超过key设置的过期时间,会执行删除操作并返回空,这种策略是出于节省CPU成本考虑,不需要单独维护TTL链表来处理过期key的删除 定时任务删除:redis内部维护一个定时任务,默认每秒运行10次(通过配置hz控制),定时任务在每个数据库空间随机检查20个key,发现过期时删除对应的key 内存溢出控制策略:redis支持6种淘汰策略: maxmemory-policy 是Redis配置文件中的一个参数,用于设置当内存使用达到 maxmemory 设置的最大值时,Redis应该采取什么样的策略来回收内存。

以下是maxmemory-policy参数的值:

  1. volatile-lru:从设置了过期时间的键中选择最少最近使用的键进行删除。这是“最近最少使用”(LRU)策略的一种变体,只考虑设置了过期时间的键。

  2. allkeys-lru:从所有键中选择最少最近使用的键进行删除。这是标准的LRU策略。

  3. volatile-random:从设置了过期时间的键中随机选择键进行删除。

  4. allkeys-random:从所有键中随机选择键进行删除。

  5. volatile-ttl:优先删除那些TTL(Time To Live,生存时间)值较小的键,也就是说,优先删除那些即将过期的键。

  6. noeviction当内存使用达到最大值时,不进行任何内存回收,而是返回错误。这是默认策略。

可以通过命令设置:

172.21.108.20:6399> config set  maxmemory-policy  allkeys-lru
OK
172.21.108.20:6399> config get maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
172.21.108.20:6399>

这些策略的选择取决于具体的使用场景。例如,如果你的Redis实例主要用于缓存,那么可能会选择volatile-lru或者allkeys-lru策略。如果你的Redis实例存储的数据都是有过期时间的,那么可能会选择volatile-ttl策略。如果你的Redis实例主要用于持久化存储,那么可能会选择noeviction策略。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  eHipUjOuzYYH   2023年12月07日   27   0   0 数据乐观锁redis
  jnZtF7Co41Wg   2023年12月06日   27   0   0 sedlinux数据
  P3nxyT0LRuwj   2023年11月24日   63   0   0 缓存redis配置文件
  eHipUjOuzYYH   2023年12月06日   33   0   0 sedbootstrapIPV6
  xIUntf9oR6GI   2023年11月28日   31   0   0 sedvim基础命令
  oIa1edJoFmXP   2023年11月24日   30   0   0 AppsedVue
  9JCEeX0Eg8g4   2023年11月22日   23   0   0 数据redis持久化