前言先来看一个问题,假设Redis实例保存了5GB的数据,现在删除了2GB的数据,那么Redis进程占用的内存会不会减少?答案是:它可能仍然需要大约5GB的内存,即使Redis数据只需要大约3GB。如果maxmemory不设置该参数,Redis将不会触发内存淘汰策略删除数据。Redis会继续为新写入的数据分配内存。分配失败会导致应用程序报错,当然不会导致宕机。注意:设置maxmemory参数,执行命令CONFIGSETmaxmemory100mb,或者在redis.conf配置文件中设置maxmemory100mb。用top命令看看数据是不是已经删除了,为什么还是占用那么多内存?释放的内存去了哪里?当我们使用top命令查看系统使用情况时,会发现内存依然很高,Redis并没有真正释放内存。那么内存去哪儿了呢?这时候我们就需要使用infomemory命令来获取Redis内存相关的指标。127.0.0.1:6379>infomemory#memoryused_memory:1132832//Redis用于存储数据的内存量used_memory_human:1.08M//以人类可读的形式返回内存总量mused_memory_rss:2977792//从操作系统的角度来看,进程占用的总物理内存used_memory_rss_human:2.84M//used_memory_rssReadabilitymodedisplayused_memory_peak:1183808//使用内存的最大值,代表used_memory_memory_peak_human:1.13M的峰值//以人类可读的格式返回used_memory_peak的值used_memory_lua:37888//Lua引擎消耗的内存量。used_memory_lua_human:37.00Kmaxmemory:2147483648//可以使用的最大内存值,以字节为单位。maxmemory_human:2.00G//可读形式maxmemory_policy:noeviction//内存报废策略mem_fragmentation_ratio:2.79//used_memory_rss&used_memory的比值代表内存碎片率Redis进程的内存消耗主要由以下几部分组成:内存由Redis启动占用存储对象数据内存buffer内存:主要由client-output-buffer-limit客户端输出缓冲区、copybacklogbuffer、AOF组成buffermemoryfragmentationRedis自身的空进程占用的内存很小,可以忽略不计,而对象内存最大,里面存放了所有的数据。需要注意的是,如果buffer有大流量的场景,很容易失控,导致Redis内存不稳定。过多的内存碎片会导致可用空间不足来存储数据。MemoryFragmentation碎片=used_memory_rss实际使用的物理内存(RSS值)除以used_memory实际存储数据的内存。什么是内存碎片?内存碎片导致内存空间变得空闲,但无法存储数据。比如你和你女朋友去电影院看电影,你们一定要在一起。假设现在有8个座位,已售出4张票,还有4张可供购买。不过巧合的是,买票的人很奇怪,都是隔壁座位买票的。即使还有4个座位,也不能购买顺序连接两个座位的车票。什么导致内存碎片?主要有两个原因:内存分配器的分配策略中key-value对的大小不一样,下面会讲delete操作。1、内存分配器的分配策略Redis默认的内存分配器使用jemalloc,可选的分配器有:glibc、tcmalloc。内存分配器不是按需分配,而是使用固定范围的内存块进行分配。比如8字节,16字节...,2KB,4KB,当申请的内存最接近固定值时,jemalloc会分配最接近固定值的空间。这样会造成内存碎片。比如程序只需要1.5KB,而内存分配器会分配2KB的空间,那么这0.5KB就是碎片。这样做的目的是减少内存分配的次数。比如你申请22字节的空间来存放数据,jemalloc会分配32字节。如果后面需要写入10个字节,则不需要向操作系统申请空间。您可以使用之前请求的32个字节。当一个键被删除时,Redis不会立即将内存归还给操作系统。发生这种情况是因为底层内存分配器的管理。例如,大多数已删除的键仍与其他有效键分配在相同的内存页中。此外,为了重用空闲内存块,分配器删除了原始5GB数据中的2GB。再次向实例添加数据时,Redis的RSS会保持稳定,不会增加太多。因为内存分配器基本上重新使用了之前删除释放的2GB内存。2.键值对大小不同,删除操作是因为内存分配器是按照固定大小分配内存,所以分配的内存空间通常大于实际数据占用的大小,这会导致碎片化,降低内存的存储效率。此外,键值对的频繁修改和删除导致内存空间的扩展和释放。例如,如果一个字符串原来占用32个字节,现在修改为一个占用20个字节的字符串,那么释放出来的12个字节就是空闲空间。如果下一次数据存储请求需要申请一个13字节的字符串,刚刚释放的12字节空间就不能使用,造成碎片。分片最大的问题:空间总量足够大,但是这些内存不是连续的,可能存不下数据。mem_fragmentation_ratio=used_memory_rss/used_memory怎么解决?首先需要判断是否发生了内存碎片,重点关注执行完infomemory命令后的mem_fragmentation_ratio指标,表示内存碎片率。如果1
