当前位置: 首页 > 科技观察

如何避免内存溢出?——Redis内存使用及管理知识总结

时间:2023-03-18 19:43:49 科技观察

Redis是当今非常流行的内存数据库。我们所有的数据都保存在内存中,所以我们每次读写都是从内存中操作的。所以在带来速度的同时,也给我们带来了内存使用方面的挑战。众所周知,内存在硬件资源中的价格要高于硬盘。通过学习Redis的内存知识,我们可以在保护Redis数据库的同时更高效的发挥Redis的作用,进而管理内存,降低内存消耗和硬件成本。Redis作为一个内存数据库,有命令统计自己使用的内存。通过获取到的相关信息,可以了解Redis当前自身内存使用情况,进而有助于判断内存使用的健康度。Redis提供了查看内存为信息内存的命令。上述指标中需要重点关注的指标有:used_memory_rss和used_memory及其比率mem_fragmentation_ratio。当mem_fragmentation_ratio>1时,表示used_memory_rss-used_memory多余的内存没有用于数据存储,而是被内存碎片消耗掉了。值越大,内存碎片越多。当mem_fragmentation_ratio<1时,这种情况表明正在使用虚拟内存,即正在使用宿主机的硬盘。由于硬盘的性能远低于内存,所以要小心Redis因为性能问题导致的整体故障。根据日常使用情况,mem_fragmentation_ratio的取值在1~1.5之间比较健康。如何处理内存碎片过多的问题?最简单暴力的方法就是重启。Redis4.0版本后,支持运行时自动清理内存碎片。主要是通过设置configsetactivedefragyes来实现的,同时还提供了memorypurge命令,用于手动清理内存碎片。Redis默认使用无限内存,所以为了防止系统内存被耗尽,需要设置Redis内存上限。Redis使用maxmemory参数来限制最大可用内存。通过前面的介绍我们可以知道,maxmemory配置的是Redis实际使用的内存量,也就是used_memory统计项对应的内存。由于内存碎片率的存在,实际消耗的内存可能会比maxmemory设置的要大,所以在实际使用的时候要小心这部分内存溢出。按照惯例,一般会预留服务器20%的空闲内存,以防止内存溢出通过。Redis的内存上限可以通过configsetmaxmemory动态修改,即可以修改最大可用内存。通过动态修改maxmemory,可以达到在当前服务器下动态扩展Redis内存的目的。考虑到现在Redis的部署大多采用集群或者sentinel模式,单台主机不是Redis的单实例,所以建议所有Redis进程都必须配置maxmemory。Redis提供了内存回收策略供运维人员根据内存使用情况进行配置。主要用于当Redis内存使用量达到设定的maxmemory上限时,删除达到过期时间的key对象,执行内存回收策略。所有Redis键都可以设置过期属性。数据库结构中的expires字典存储了数据库中所有key的过期时间。我们称过期字典为过期字典。由于进程中存储了大量的key,为每个key维护一个准确的过期删除机制会消耗大量的CPU,对于单线程Redis来说代价太大。因此,Redis采用惰性删除和定时任务删除机制来实现对过期键的记忆。回收。延迟删除:当客户端读取具有超时属性的键时使用延迟删除。如果超过key设置的过期时间,则执行delete操作,返回empty。这种删除策略对CPU是友好的,删除操作只在必要的时候才会进行,不会在其他expirekey上浪费不必要的CPU时间。但是这种策略对内存并不友好。一个key已经过期,但是在操作之前不会删除,仍然占用内存空间。如果有大量的过期键却很少被访问,会造成内存空间的大量浪费。因为可能有一些key永远不会再被访问,所以这些设置了过期时间的key过期后也需要删除。我们甚至可以将这种情况视为内存泄漏——无用的垃圾数据占用了大量内存,但服务器不会自行释放它们,这对于运行状态非常依赖内存的Redis服务器来说绝对不是一个好消息。正因为如此,Redis还提供了另一种定时任务删除机制,作为懒删除的补充。定时任务删除:Redis内部维护了一个定时任务,默认每秒运行10次(通过配置server.hz控制)。Redis会周期性随机测试一批设置了过期时间的key,并进行处理。已过期的测试密钥将被删除。当Redis使用的内存达到maxmemory的上限时,就会触发相应的溢出控制策略。具体策略由maxmemory-policy参数控制。Redis支持6种策略,如下:1)noeviction:默认策略,数据永不过期,不会删除任何数据。当内存不足以容纳新写入的数据时,新的写入输入操作会报错,一般不推荐使用。2)volatile-lru:根据LRU算法删除设置了超时属性(expire)的key,直到有足够的空间。如果无法删除关键对象,则回退到noeviction策略。在这种情况下,Redis一般既作为缓存,又作为持久化存储。3)allkeys-lru:按照LRU算法删除key,不管数据是否设置了timeout属性,直到腾出足够的空间。一般推荐使用这种策略4)allkeys-random:当内存不足以容纳新写入的数据时,从key空间中随机取出一个Key。5)volatile-random:当内存不足以容纳新写入的数据时,从key空间中随机移除一个key,并设置过期时间。6)volatile-ttl:当内存不足以容纳新写入的数据时,在设置了过期时间的key空间中,先删除过期时间较早的Key。如果不是,则退回到noeviction策略。可以使用configsetmaxmemory-policy{policy}动态配置内存溢出控制策略。上面我们介绍了Redis支持的内存溢出响应策略,运维人员可以根据实际需要灵活定制。综上所述,我们从Redis数据库最关键的特性——内存出发,详细介绍了Redis的内存使用和内存管理,这也是一个专业的Redis运维人员的核心技能。通过这篇文章,可以提高你对Redis内存的理解,但是要真正掌握它还需要很长时间的学习和使用。希望大家一起努力学习进步。