Redis 的内存优化

摘要:redis 的内存优化,缩减键值对象,尽量使用整数,定期检测不用的键并删除,编码优化,控制键的数量。

缩减键值对象

优化 redis 内存最有效的最直接方式就是缩短 key 和 value 的长度。key 要在符合业务描述完整性的情况下越短越好,value 的存储,把业务对象化序列化(php 系统函数:serialize、unserialize)成二进制数组放入 redis,在序列化工具上选择更有效的工具来降低字节数组的大小。

精简业务,避免存储不必要的属性或者元素存储。

我们一般会在 redis 中存储通用的 json、xml 格式的数据,但是如果在内存紧张的情况下可以使用通用压缩算法压缩 json、xml 后再存储 redis 中,从而降低内存占用,例如使用 gzip 压缩后可降低 60% 的空间,当频繁操作压缩和解压数据的时候,要考虑频繁的压缩带来的开销成本。


尽量使用数字存储

因为 redis 内部维护 0 - 9999 的数字共享内存池,用于节约内存,这个配置在 server.h 源码文件可以更改。

具体 redis 的共享内存请看这篇文章:Redis 的 redisObject 对象结构


检测不用的键并删除

了解过 redis 的内存管理和内存淘汰策略:Redis 的内存管理和内存过期策略,就知道 redis 是依靠定期删除、惰性删除、内存淘汰策略等方案淘汰 redis 过期的 key,用于保持 redis 内存中对象的活跃度和释放优化内存。

这些 redis 自带方案的方案中,定期删除时每隔一段时间检测一下,难免有检测不到的。惰性删除是主动触发的,如果没有主动触发,还是不会删除。内存淘汰策略是内存到达 maxmemory 上限才会触发淘汰策略。

所以我们可以使用 scan + object idletime key 命令 + lua 脚本删除一些过期的键或者是过期时间很长的键。scan 命令可以批量的遍历所有的 key,直到返回 0 遍历结束。object idletime key 命令返回的 key 空闲时间是以秒为单位。此方法帮助内存淘汰机制的 lru 算法找出长时间不访问的键进行清理,可降低内存占用。

具体操作:REDIS清理死键


内存碎片优化

内存碎片优化,应该先了解下 redis 内存分配原则,为什么会产生内存碎片,如何尽量避免产生碎片等,优化方案如下。

数据对其:在条件允许的情况下采取数据对齐,比如数据尽量采取定长或者固定长度字符串等。

安全重启:所谓安全重启,比如利用高可用架构,把碎片率过高的主节点变成从节点然后安全重启,重启节点可以做到内存碎片的重新整理。


字符串重构

比如一个数据我们要序列化成 json 然后使用字符串数据类型存储,对于这种有结构的数据,我们可以直接使用 hash 存储,使用二级结构存储也能帮我们节省内存。同时可以使用 hmget、hmset 命令支持字段的部分读取修改,而不用每次整体存取。


# 编码优化

1、同样的数据使用 ziplist 编码的 hash 类型存储比 string 类型节约内存。

2、ziplist 适合存储小对象, 对于大对象不但内存优化效果不明显还会增加命令操作耗时。

3、根据 hash 长度和元素大小, 调整 hash-max-ziplist-entries 和 hash-maxziplist-value 参数, 确保 hash 类型使用 ziplist 编码。

4、编码类型是在 redis 内部自动完成,这种转换不可逆,转换只能从小内存向大内存转换,redis 不支持编码回退,主要是数据增删频繁时,数据向压缩编码转换非常消耗 cpu,得不偿失。


# 控制键的数量

redis 的 key 很多也会消耗大量的内存,我们可以使用 hash 结构,将大量的键映射到多个 hash 结构中降低键的数量。

1、比如存在 100 万个键, 可以映射到 1000 个 hash 中, 每个 hash 保存 1000 个元素。

2、hash 的 field 可用于记录原始 key 字符串, 方便哈希查找。

3、hash 的 value 保存原始值对象, 确保不要超过 hash-max-ziplist-value 限制。

使用 ziplist+hash 优化 keys 后, 如果想使用超时删除功能, 开发人员可以存储每个对象写入的时间, 再通过定时任务使用 hscan 命令扫描数据, 找出 hash 内超时的数据项删除即可。

以上的几个优化的点只是垂直层面的优化,如果垂直优化已经遇到瓶颈,那么就需要增加内存或者横向增加服务器来水平扩展了。

结束语:感谢您对本网站文章的浏览,欢迎您的分享和转载,但转载请说明文章出处。
Top