Redis学习目录总结08-Redis内存空间占用优化

155 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

Redis内存优化

删除过期键对象

  • 可以使用 scan + object idletime 命令批量查询哪些键长时间未被访问,找出长时间不访问的键进行清理,可降低内存占用。

  • 高并发写入场景中,在条件允许的情况下,建议字符串长度控制在39字节以内 ,减少创建redisObject 内存分配次数,从而提高性能。

Redis所有的键都可以设置过期属性,内部保存在过期字典中。由于进程内保存大量的键,维护每个键精准的过期删除机制会导致消耗大量的CPU, 对于单线程的Redis来说成本过高,因此Redis采用惰性删除和定时任务删除机制实现过期键的内存回收

  • 惰性删除:惰性删除用于当客户端读取带有超时属性的键时,如果已经超过键设置的过期时间,会执行删除操作并返回空,这种策略是出于节省CPU成本考虑,不需要单独维护TTL链表来处理过期键的删除。但是单独用这种方式存在内存泄露的问题,当过期键一直没有访问将无法得到及时删除,从而导致内存不能及时释放。正因为如此,Redis还提供另一种定时任务删除机制作为惰性删除的补充。

  • 定时任务删除:Redis内部维护一个定时任务,默认每秒运行10次 (通过配置hz控制)。定时任务中删除过期键逻辑采用了自适应算法,根据键的过期比例、使用快慢两种速率模式回收键,流程如图8-4所示。

利用jemalloc特性进行优化

例如,如果key的长度如果是8个字节,则SDS为17字节,jemalloc分配32字节;此时将key长度缩减为7个字节,则SDS为16字节,jemalloc分配16字节;则每个key所占用的空间都可以缩小一半。

使用整型/长整型

如果是整型/长整型,Redis会使用int类型(8字节)存储来代替字符串,可以节省更多空间。因此在可以使用长整型/整型代替字符串的场景下,尽量使用长整型/整型。

共享对象

利用共享对象,可以减少对象的创建(同时减少了redisObject的创建),节省内存空间。目前redis中的共享对象只包括10000个整数(0-9999);可以通过调整REDIS_SHARED_INTEGERS参数提高共享对象的个数;例如将REDIS_SHARED_INTEGERS调整到20000,则0-19999之间的对象都可以共享。

内存溢出控制策略

当Redis所用内存达到maxmemory上限时会触发相应的溢出控制策略。具体策略受maxmemory-policy参数控制,Redis支持6种策略,如下所示:

  • noeviction: 默认策略,不会删除任何数据,拒绝所有写人操作并返回客户端错误信息(error) OOM command not allowed when used memory, 此时 Redis 只响应读操作。

  • volatile-lru: 根据LRU算法删除设置了超时属性(expire) 的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction 策略。

  • allkeys-lru: 根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。

  • allkeys-random: 随机删除所有键,直到腾出足够空间为止。

  • volatile-random: 随机删除过期键,直到腾出足够空间为止。

  • vlatile-ttl : 根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。

内存溢出控制策略可以采用config set maxmemory-policy {policy}动态配置。Redis支持丰富的内存溢出应对策略,可以根据实际需求灵活定制,比如当设置volatile-lru策略时,保证具有过期属性的键可以根据LRU剔除,而未设置超时的键可以永久保留。还可以采用allkeys-lru策略把Redis变为纯缓存服务器使用。当 Redis因为内存溢出删除键时,可以通过执行info stats命令查看evicted _keys指标找出当前Redis服务器已剔除的键数量。

每次Redis执行命令时如果设置了maxmemory参数,都会尝试执行回收内存操作。当Redis—直工作在内存溢出(used_memory>maxmemory) 的状态下且设置非noeviction策略时,会频繁地触发回收内存的操作,影响Redis服务器的性能。