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。lua

used_memory_peak:  内存使用的峰值。spa

used_memory_peak_human:  以可读的格式返回used_memory_peak。操作系统

total_system_memory:  系统可用内存总量。3d

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不一样类型对象的存储和管理

相关文章
相关标签/搜索