Redis开发与运维之第八章理解内存(五)

insert编码

是集合(set)的类型编码的一种,内部表现为存储有序、不重复的整数集。当集合只包含整数且长度不超过set-max-intset-entries 配置时被启用。执行以下命令查看intset表现:

redis> sadd set:test 3 4 2 6 8 9 2
(integer) 6
redis> object encoding set:test
"intset"
redis> smembers set:test
"2" "3" "4" "6" "8" "9"
redis> config set set-max-intset-entries 6
OK
redis> sadd set:test 5
"hashtable"
redis> smembers set:test
"8" "3" "5" "9" "4" "2" "6"

以上命令可以看出intset对写入整数进行排序,通过O(logn)时间复杂度实现查找和去重操作,intset编码结构如图所示:

  

字段结构含义:

1. encoding:整数表示类型,根据结合内最长整数值确定类型,整数类型划分为三种,int-16/int-32/int-64

2. length:表示集合元素个数。

3. contents: 整数数组、按从小到大顺序保存。

intset保存的整数类型根据长度划分,当保存的整数超出当前类型时,将会触发自动升级操作且升级后不再做回退。

升级操作将会导致重新申请内存空间,把原有数据按转换类型后拷贝到新数组中。

控制键的数量

当使用redis存储大量数据时,通常会存在大量键,过多的键同样会消耗大量内存。Redis本质是一个数据结构服务器,它为我们提供多种数据结构,如hash、list、set、zset等。使用Redis时不要进入一个误区,大量使用get/set/这样的API,把redis当错memcached使用。

对于存储相同的数据内容利用Redis的数据结构降低外层键的数量,也可以节省大量内存。如图所示,通过在客户端预估键规模,把大量键分组映射到多个hash结构中减低键的数量。

 hash结构降低键数量分析:

1. 根据键规模在客户端通过分组映射到一组hash对象中,如存在100万个键,可以映射到1000个hash中,每个hash保存1000个元素。

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

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

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

节省内存量随着value空间的减少越来越明显。

hash-ziplist类型比string类型写入耗时,但随着value空间的减少,耗时逐渐降低。

使用hash重构后节省内存量效果非常明显,特别对于存储小对象的场景,内存只有不到原来的1/5 。下面分析这种内存优化技巧的关键点;

1. hash类型节省内存的原理是使用ziplist编码,如果使用hashtable编码方式反而会增加内存消耗。

2  ziplist长度需要控制在1000以内,否则由于存储操作时间复杂度在O(n) 到O(n2)之间,长列表会导致CPU消耗严重,得不偿失。

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

4. 需要预估键的规模,从而确定每个hash结构需要存储的元素数量

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

关于hash键和field键的设计:

1. 当键离散度较高时,可以按字符串位截取,把后三位作为哈希的field,之前部分作为哈希的键。

如:key=1948480哈希key=group:hash:1948,哈希field=480。

2. 当键离散度较低时,可以使用哈希算法打散键,

如:使用crc32(key)&10000函数把所有的键映射到“0-9999”整数范围内,哈希field存储键的原始值。

3. 尽量减少hash键和field的长度,如使用部分键内容

使用hash结构控制键的规模虽然可以大幅降低内存,但同样会带来问题,需要提前做好规避处理

1. 客户端需要预估键的规模并设计hash分组规则,加重客户端开发成本。

2. hash重构后所有的键无法再使用超时(expire)和LRU淘汰机制自动删除,需要手动维护删除

3. 对于大对象,如1KB以上的对象,使用hash-ziplist结构控制键数量反而得不偿失

4. 对于大量小对象的存储场景,非常适合使用ziplist编码的hash类型控制键的规模来降低内存

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章