Redis有自己的内存分配器,当key-value对象被移除时,Redis不会马上向操作系统释放其占用内存。redis之所以这样的设计有两个原因。
- OS可能会将释放内存交换到虚拟内存,但OS的虚拟内存又是物理文件,其IO读写效率较低,从而影响Redis性能表现
- OS的虚拟内存换入换出是基于Page机制,同一Page内的部分数据对象被释放,但其他数据对象依然被其他应用使用中,导致在该Page内的Redis对象没有被释放
而Redis作者应该是考虑到以上问题,不希望Redis由此降低性能,所以在设计上Redis更倾向于自己掌控VM换入的粒度。
内存监控
启动redis-cli,info命令可以观察Redis实例的运行情况,其中# Memory块查看内存使用情况。
# Memoryused_memory:26355360#当前Redis所有key-value值及内部开销理论上要占用的内存used_memory_human:25.13M#上一数据的可读版本used_memory_rss:28127232##(Resident Set Size常驻数据集大小),可理解为OS为Redis分配的物理内存总量used_memory_rss_human:26.82Mused_memory_peak:26355360#峰值内存used_memory_peak_human:25.13M#峰值内存可读版本total_system_memory:8253997056total_system_memory_human:7.69Gused_memory_lua:37888#lua引擎占用内存used_memory_lua_human:37.00Kmaxmemory:0maxmemory_human:0Bmaxmemory_policy:noevictionmem_fragmentation_ratio:1.07#内存碎片率,used_memory_rss 和 used_memory 之间的比率mem_allocator:jemalloc-4.0.3#所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc
其中mem_fragmentation_ratio(内存碎片率)是分析Redis性能的重要数据指标
- 大于1:OS为Redis分配的物理内存 > Redis所有key-value值及内部开销应占用的内存
产生原因:物理内存多出的部分,Redis内移除对象的占用内存,但这部分内存由Redis自带内存分配器占用,没有向操作系统返回。这一部分就是内存碎片
- 小于1:OS为Redis分配的物理内存 < Redis所有key-value值及内部开销理应占用的内存
产生原因:应占内存比物理内存多出的部分,是被操作系统交换到虚拟内存,说明当前Redis的内存使用已经超出物理内存
内存碎片率保持在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峰值)。
maxmemory的单位是bytes,默认为0,即不限制最大内存。
内存限制与Key回收
除maxmemory以外,仍然需要指定Redis在最大内存溢出后的处理行为——maxmemory-policy。同时设置了maxmemory与maxmemory-policy选项,redis内存使用达到上限。可以通过设置LRU算法(Least Recently Used 近期最少使用算法)来删除部分key,释放空间
提示: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 -> 谁也不删,直接在写操作时返回错误。