Redis内存优化二
这一节我们继续说Redis内存优化 上一节我们说了key的优化以及整数对象池的相关知识
下面我们说一说字符串的优化
字符串的优化
Redis中使用的字符串实现 叫SDS 结构如下
len 已用长度
feeLen 未用长度
char[] 字节数组
获取这几个属性的时间复杂度都是O(1)
同时我们要知道 SDS的内存预分配机制 就是第一次set的时候 len就是字符串长 freeLen=0
当采用append等命令修改字符串时间redis为对字符串的空间进行扩容 然后再把追加的字符串放入其中,这种预分配机制扩容的长度通常要大于追加的字符串,这就会造成内存的浪费 所以在使用的时候尽量直接set 不要追加 避免重复预分配内存造成的损耗
编码优化
redis提供了5种数据类型 string hash list set zset 每种类型在redis实现中都至少有两种内部编码实现
为什么这么做? 最重要的原因是为了追求效率与空间的平衡 不同的编码所占用的内存空间差异很大 所以合理的使用内部编码对于内存优化有很大的帮助 下面我们来聊一聊
查看当前key的内部编码实现 object encoding key
例
set hello 'world'
object encoding hello -> embstr 说明此时redis内部使用embstr这种实现来存储world字符串
同一种数据类型既然有两种或以上的内部 实现 那使用哪一种由什么确定呢?
通常来说跟数据长度及大小有关
举例:
对于hash这种类型
当存储的哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个),同时所有值都小于hash-max-ziplist-value配置(默认64字节) 时使用的内部实现 是ziplist 一旦其中某个参数超过阈值 内部实现就更改为 hashtable ,而hashtable会占用更大的内存空间
编码的转换是在redis写入的时候自动完成的,并且只能从小内存编码向大内存编码转换 不能降级

再来简单说一说 ziplist这种编码
ziplist主要特点是占用内存空间 小 它采用线性连续的内存空间
同时它可以作为多种数据类型的实现 如 hash list zset
ziplist 内部有多个entry 每个entry保存具体的数据
新增和删除操作会涉及内存的重新分配和释放 加大了操作的复杂性
同时读写操作的复杂度为O(n2) 所以适用于小对象和长度有限的数据使用
最后还有一点 在使用redis的过程中我们要尽量控制键的数量
如果键过多也会消耗大量内存
键过多的情况下我们可以考虑会使用hash来存储 把一部键当做hash的field来存储
当然要确保hash元素不要过多 保证底层的实现是使用ziplist的 否则会得不偿失
使用ziplist+hash优化keys后,如果想使用超时删除功能,开发人员可以存储每个对象写入的时间,再通过定时任务使用hscan命令扫描数据,找出hash内超时的数据项删除即可。