[关闭]
@zero1036 2018-09-10T09:24:16.000000Z 字数 2975 阅读 2792

Redis

Redis内存优化--分配监控回收


内存分配

物理内存:就是主机安装的物理内存条,一般32位的CPU有32条地址线,最大寻址空间就是4G,而64位的CPU则能够支持更大的内存。可是,再大的内存,也有可能满足不了所有应用的内存需要;又或者是,大量使用频率极低的冷数据占用了大部分物理内存。这个时候,就是“虚拟内存”出场了。

虚拟内存(简称VM):由操作系统OS管理,本质就是硬盘中的一个特殊格的磁盘分区、或者一个文件(linux下是swap分区、windows下是ib3文件),其写入写出由OS掌管,如果出现以上两种情景,OS会将溢出物理内存部分数据或者部分冷数据交换到虚拟内存,释放更多空间提供其他应用运作。而对于所有应用而言,其运行可使用的内存理论上是:物理内存 + 虚拟内存

Redis跟所有的应用一样,其内存分配都是要由OS来管理。用户增加key-value对象,Redis则向OS申请内存划分到应用;反之,用户移除key-value对象,Redis向OS返还内存,并由OS决定该将热数据放入物理内存,冷数据交换到硬盘。

不一样的是,Redis有自己的内存分配器,当key-value对象被移除时,Redis不会马上向操作系统释放其占用内存(例如,当用户往一个实例填充了5G的数据,移除其中2G数据,但占用内存可能仍会保持在5G左右)。为什么Redis要这样处理?有两个原因:

1、OS可能会将释放内存交换到VM,但OS的VM又是物理文件,其IO读写效率较低,从而影响Redis性能表现;

2、OS的VM换入换出是基于Page机制,同一Page内的部分数据对象被释放,但其他数据对象依然被其他应用使用中,导致在该Page内的Redis对象没有被释放。

而Redis作者应该是考虑到以上问题,不希望Redis由此降低性能,所以在设计上Redis更倾向于自己掌控VM换入的粒度。

内存监控

redis-cli > info

![图片描述][1]

启动redis-cli,info命令可以观察Redis实例的运行情况,其中# Memory块查看内存使用情况。

提示:以上used_memory数据所包含的内存均包含有:

* 用户定义的数据:内存被用来存储key-value值。
* 内部开销: 存储内部Redis信息用来表示不同的数据类型。

再来看看具体每个数据所指具体含义

其中mem_fragmentation_ratio(内存碎片率)是分析Redis性能的重要数据指标,计算公式是:

![图片描述][2]

大于1:OS为Redis分配的物理内存 > Redis所有key-value值及内部开销应占用的内存

产生原因:物理内存多出的部分,Redis内移除对象的占用内存,但这部分内存由Redis自带内存分配器占用,没有向操作系统返回。这一部分就是内存碎片。

小于1:OS为Redis分配的物理内存 < Redis所有key-value值及内部开销理应占用的内存

产生原因:应占内存比物理内存多出的部分,是被操作系统交换到虚拟内存,说明当前Redis的内存使用已经超出物理内存

问题是,这个ratio比率,多少比值最合理?回顾前文,Redis是自带内存分配器的,自带内存分配器会保留内部已释放的内存,目的是为了避免操作系统低性能交换,当然它也是比较灵活的,被释放的内存块是可以被重用。翻阅了下官方文档,也有对应的说明

* However allocators are smart and are able to reuse free chunks of memory, so after you freed 2GB of your 5GB data set, when you start adding more keys again, you’ll see the RSS (Resident Set Size) to stay steady and don’t grow more, as you add up to 2GB of additional keys. The allocator is basically trying to reuse the 2GB of memory previously (logically) freed.

因此,内存碎片率保持在1.0至1.5之间是最理想的状态。假若碎片率超过了1.5,我所知道的最有效解决手段就是重启Redis服务器,释放内存回到操作系统;反之,若碎片率为0.9,说明物理内存已不够用,应增添硬件,或设置Redis最大内存限制maxmemory

最大内存限制maxmemory的设置非常重要,如果不设置maxmemory,Redis一直会为其分配内存,直至耗尽所有物理内存,直到操作系统进行虚拟内存交换。因此,一般情况下,作者建议还是把峰值设置设上。开启此配置,当超出限定内存情况发生,Redis会返回异常消息,操作系统不会因内存溢出而奔溃。还有一点建议是,开发者在系统设计之初,就应当制定Redis内存使用划分计划,而划分原则是,为Redis准备系统可能使用的峰值内存,而不是平均使用内存。例如系统大部分情况会以Redis作为分布式缓存写入10G数据,但大部分情况下只会跑到4G,但Redis依然推荐用户为其预留10G内存(used_memory_peak峰值)。

redis.conf--> maxmemory 10000000

maxmemory的单位是bytes,默认为0,即不限制最大内存。

内存限制与Key回收

maxmemory以外,仍然需要指定Redis在最大内存溢出后的处理行为——maxmemory-policy。同时设置了maxmemorymaxmemory-policy选项,redis内存使用达到上限。可以通过设置LRU算法(Least Recently Used 近期最少使用算法)来删除部分key,释放空间。相关内容参考:[将redis当做使用LRU算法的缓存来使用][3]。

提示:Redis32位实例最大可用内存为3G,64位则无限制,而RDB与AOF持久化文件都兼容支持32位或64位实例,因此可以自由切换在32位与64位之间切换。

volatile-lru -> 根据LRU算法生成的过期时间来删除。
allkeys-lru -> 根据LRU算法删除任何key。
volatile-random -> 根据过期设置来随机删除key。
allkeys-random -> 无差别随机删。
volatile-ttl -> 根据最近过期时间来删除(辅以TTL)
noeviction -> 谁也不删,直接在写操作时返回错误。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注