Redis深入学习笔记Redis内存分配
Posted 羽风蓝
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis深入学习笔记Redis内存分配相关的知识,希望对你有一定的参考价值。
Redis的高效可以说是轻量级的epoll模型和基于内存的读写共同组成的,关于epoll对于以前的select或者poll的性能优势这里不做介绍,本篇主要介绍领一个重点,Redis的内存分配原理。
获取内存信息命令:info memory
used_memory: Redis分配器分配的内存总量,就是内部存储的所有数据内存占用量。
used_memory_human: 以可读的格式返回used_memory。
used_memory_rss: 以操作系统同的角度显示Redis进程占用的物理内存总量。
used_memory_rss_human: 以可读的格式返回used_memory_rss。
used_memory_peak: 内存使用的峰值。
used_memory_peak_human: 以可读的格式返回used_memory_peak。
total_system_memory: 系统可用内存总量。
total_system_memory_human: 以可读的格式返回total_system_memory。
used_memory_lua: lua引擎消耗的内存总量。
used_memory_lua_human: 以可读的格式返回used_memory_lua。
maxmemory: Redis最大可用内存。
maxmemory_human: 以可读的格式返回maxmemory。
maxmemory_policy: 达到最大可用内存时使用的淘汰策略。
mem_fragmentation_ratio: used_memory_rss/used_memory比值,标识碎片率。
mem_allocator: Redis使用的内存分配器,默认是jemalloc。
重要指标:used_memory_rss和used_memory以及它们的比值mem_fragmentation_ratio。
当mem_fragmentation_ratio>1时,说明used_memory_rss-used_memory多出的部分内存并没有用于数据存储,而是被内存碎片所消耗,如果两者相差很大,说明碎片率严重。
当mem_fragmentation_ratio<1时,这种情况一般出现在操作系统把Redis内存交换(Swap)到硬盘导致,出现这种情况时要格外关注,由于硬盘速度远远慢于内存,Redis性能会变得很差,甚至僵死。
内存分配图:
自身内存:Redis运行自身使用的内存
对象内存:用户数据
缓冲内存:客户端缓冲、复制积压缓冲区、AOF缓冲区
客户端缓冲:指的是所有接入到Redis服务器TCP连接的输入输出缓冲。输入缓冲无法控制,最大空间为1G,如果超过将断开连接。输出缓冲通过参数client-output-buffer-limit控制。输入输出缓冲区在大流量的场景中容易失控,造成Redis内存的不稳定,需要重点监控。
普通客户端:除了复制和订阅的客户端之外的所有连接,Redis的配置项是:client-output-buffer-limit。Redis并没有对普通客户端的输出缓冲区做限制,一般普通客户端的内存消耗可以忽略不计,但是当有大量慢连接客户端接入时这部分内存消耗就不能忽略了,可以设置maxclients做限制。特别是当使用大量数据输出的命令且数据无法及时推送给客户端时,如monitor命令,容易造成Redis服务器内存突然飙升。
从客户端:主节点会为每个从节点单独建立一条连接用于命令复制,配置项是:client-output-buffer-limit。当主从节点之间网络延迟较高或主节点挂载大量从节点时这部分内存消耗将占用很大一部分,建议主节点挂载的从节点不要多于2个,主从节点不要部署在较差的网络环境下,如异地跨机房环境,防止复制客户端连接缓慢造成溢出。
订阅客户端:当使用发布订阅功能时,连接客户端使用单独的输出缓冲区,配置项为:client-output-buffer-limit,当订阅服务的消息生产快于消费速度时,输出缓冲区会产生积压造成输出缓冲区空间溢出。
复制积压缓冲区:Redis在2.8版本之后提供了一个可重用的固定大小缓冲区用于实现部分复制功能,根据repl-backlog-size参数控制,默认1MB。对于复制积压缓冲区整个主节点只有一个,所有的从节点共享此缓冲区,因此可以设置较大的缓冲区空间,如100MB,这部分内存投入是有价值的,可以有效避免全量复制。
AOF缓冲区:这部分空间用于在Redis重写期间保存最近的写入命令。AOF缓冲区空间消耗用户无法控制,消耗的内存取决于AOF重写时间和写入命令量,这部分空间占用通常很小。
内存碎片:
Redis默认的内存分配器采用jemalloc,在64位系统中将内存空间划分为:小、大、巨大三个范围。每个范围内又划分为多个小的内存块单位,如下所示:
小:[8byte],[16byte,32byte,48byte,...,128byte],[192byte,428256byte,...,512byte],[768byte,1024byte,...,3840byte]
大:[4KB,8KB,12KB,...,4072KB]
巨大:[4MB,8MB,12MB,...]
大量过期键删除,键对象过期删除后,释放的空间无法得到充分利用,导致碎片率上升。重启节点可以做到内存碎片重新整理,因此可以利用高可用架构,如Sentinel或Cluster,将碎片率过高的主节点转换为从节点,进行安全重启。
子进程内存消耗:
子进程内存消耗主要指执行AOF/RDB重写时Redis创建的子进程内存消耗。Redis执行fork操作产生的子进程内存占用量对外表现为与父进程相同,理论上需要一倍的物理内存来完成重写操作。但Linux具有写时复制技术(copy-on-write),父子进程会共享相同的物理内存页,当父进程处理写请求时会对需要修改的页复制出一份副本完成写操作,而子进程依然读取fork时整个父进程的内存快照。
Linux Kernel在2.6.38内核增加了Transparent Huge Pages(THP)机制,而有些Linux发行版即使内核达不到2.6.38也会默认加入并开启这个功能,如Redhat Enterprise Linux在6.0以上版本默认会引入THP。虽然开启THP可以降低fork子进程的速度,但之后copy-on-write期间复制内存页的单位从4KB变为2MB,如果父进程有大量写命令,会加重内存拷贝量,从而造成过度内存消耗。
子进程内存消耗需要注意:
Redis产生的子进程并不需要消耗1倍的父进程内存,实际消耗根据期间写入命令量决定,但是依然要预留出一些内存防止溢出。
需要设置sysctl vm.overcommit_memory=1允许内核可以分配所有的物理内存,防止Redis进程执行fork时因系统剩余内存不足而失败。
排查当前系统是否支持并开启THP,如果开启建议关闭,防止copy-on-write期间内存过度消耗。
下一篇会介绍Redis不同类型对象的存储和管理
以上是关于Redis深入学习笔记Redis内存分配的主要内容,如果未能解决你的问题,请参考以下文章
Redis学习笔记20——删除数据后,为什么内存占用率还是很高?
Redis学习笔记20——删除数据后,为什么内存占用率还是很高?