第8章 理解内存
8.1 内存消耗
-
对象内存
对象内存是Redis内存占用最大的一块,存储着用户所有的数据。Redis所有的数据都采用key-value数据类型,每次创建键值对时,至少创建两个类型对象:key对象和value对象。对象内存消耗可以简单理解为sizeof(keys)+sizeof(values)。键对象都是字符串,在使用Redis时很容易忽略键对内存消耗的影响,应当避免使用过长的键,value对象更复杂些,主要包含5种基本数据类型:字符串、列表、哈希、集合、有序集合。其他数据类型都是建立在这5种数据结构之上实现的,每种value对象类型根据使用规模不同,占用内存不同。在使用时一定要合理预估并监控value对象占用情况,避免内存溢出。 -
缓冲内存
2.1缓冲内存主要包括:客户端缓冲、复制积压缓冲区、AOF缓冲区。
客户端缓冲指的是所有接入到Redis服务器TCP连接的输入输出缓冲。输入缓冲无法控制,最大空间为1G,如果超过将断开连接。输出缓冲通过参数client-output-buffer-limit控制
2.2复制积压缓冲区:Redis在2.8版本之后提供了一个可重用的固定大小缓冲区用于实现部分复制功能,根据repl-backlog-size参数控制,默认1MB。对于复制积压缓冲区整个主节点只有一个,所有的从节点共享此缓冲区,因此可以设置较大的缓冲区空间,如100MB,这部分内存投入是有价值的,可以有效避免全量复制2.3AOF缓冲区:这部分空间用于在Redis重写期间保存最近的写入命令,具体细节见5.2节。AOF缓冲区空间消耗用户无法控制,消耗的内存取决于AOF重写时间和写入命令量,这部分空间占用通常很小。
-
内存碎片
8.2 内存管理
8.2.1设置内存上限
- ·用于缓存场景,当超出内存上限maxmemory时使用LRU等删除策略释放空间。
- ·防止所用内存超过服务器物理内存。
8.2.2 动态调整内存上限
- Redis的内存上限可以通过config set maxmemory进行动态修改,即修改最大可用内存
8.2.3 内存回收策略
Redis的内存回收机制主要体现在以下两个方面:
- 删除到达过期时间的键对象。
惰性删除:惰性删除用于当客户端读取带有超时属性的键时,如果已经超过键设置的过期时间,会执行删除操作并返回空,这种策略是出于节省CPU成本考虑,不需要单独维护TTL链表来处理过期键的删除。但是单独用这种方式存在内存泄露的问题,当过期键一直没有访问将无法得到及时删除,从而导致内存不能及时释放。正因为如此,Redis还提供另一种定时任务删除机制作为惰性删除的补充。
定时任务删除:Redis内部维护一个定时任务,默认每秒运行10次(通过配置hz控制)。定时任务中删除过期键逻辑采用了自适应算法,根据键的过期比例、使用快慢两种速率模式回收键
1.定时任务在每个数据库空间随机检查20个键,当发现过期时删除对应的键。
2.如果超过检查数25%的键过期,循环执行回收逻辑直到不足25%或运行超时为止,慢模式下超时时间为25毫秒。
3.如果之前回收键逻辑超时,则在Redis触发内部事件之前再次以快模式运行回收过期键任务,快模式下超时时间为1毫秒且2秒内只能运行1次。
4.快慢两种模式内部删除逻辑相同,只是执行的超时时间不同。
2.内存溢出控制策略
当Redis所用内存达到maxmemory上限时会触发相应的溢出控制策略。具体策略受maxmemory-policy参数控制,Redis支持6种策略,如
1)noeviction:默认策略,不会删除任何数据,拒绝所有写入操作并返回客户端错误信息(error)OOM command not allowed when used memory,此时Redis只响应读操作
2)volatile-lru:根据LRU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。
3)allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。
4)allkeys-random:随机删除所有键,直到腾出足够空间为止。
5)volatile-random:随机删除过期键,直到腾出足够空间为止。
6)volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略
8.3 内存优化
-
·优化字符串使用,避免预分配造成的内存浪费,见需求是把业务对象序列化成二进制数组放入Redis
-
编码优化,不同编码实现效率和空间的平衡
我们的存储只有10个元素的列表,当使用双向链表数据结构时,必然需要维护大量的内部字段如每个元素需要:前置指针,后置指针,数据指针等,造成空间浪费,如果采用连续内存结构的压缩列表(ziplist),将会节省大量内存,而由于数据长度较小
-
控制键的数量
8.4 本章重点回顾
1)Redis实际内存消耗主要包括:键值对象、缓冲区内存、内存碎片。
2)通过调整maxmemory控制Redis最大可用内存。当内存使用超出时,
根据maxmemory-policy控制内存回收策略。
3)内存是相对宝贵的资源,通过合理的优化可以有效地降低内存的使
用量,内存优化的思路包括:
- 精简键值对大小,键值字面量精简,使用高效二进制序列化工具。
- ·使用对象共享池优化小整数对象。
- ·数据优先使用整数,比字符串类型更节省空间。
- ·优化字符串使用,避免预分配造成的内存浪费。
- ·使用ziplist压缩编码优化hash、list等结构,注重效率和空间的平衡。
- ·使用intset编码优化整数集合。
- ·使用ziplist编码的hash结构降低小对象链规模