上篇文章:
Redis常用的数据类型有string、list、set、zset(有序集合)、hash这五种,但是为了数据结构能使用在一些特殊场景,Redis在底层实现的时候会进行一定的优化。比如对于hash,Redis承诺对于使用hash的增删改查都是O(1)复杂度,但是底层实现是否还是传统的哈希表就不一定了。
1 数据类型编码方式
Redis会自适应的根据value的数据类型来使用对应的编码方式。
数据类型 |
内部编码 |
string |
raw |
int |
|
embstr |
|
hash |
hashtable |
ziplist |
|
list |
linkedlist |
ziplist |
|
set |
hashtable |
intset |
|
zset |
skiplist |
ziplist |
(1)string在内部实现有3种编码方式:
raw表示就是原生的string(对应java的字节数组),大于39字节()的string。
int是当存储的value是整数时采用的编码实现(比如存储点赞数),8字节长整型。
embstr是存储较短的string采用的编码方式(较长的string使用raw),小于等于39字节的string。
(2)hash在redis底层实现有2种编码方式:
hashtable即是使用哈希表实现(哈希函数来映射)。
ziplist是压缩列表实现,压缩列表本质是列表,但是经过压缩(压缩算法:将原来的内容重新编码,从而得到更小更短的表示),节省内存,适用于元素比较少的时候。此时对hash查找时是遍历的方式,由于元素比较少,因此遍历的时间复杂度接近O(1),用户感知不到。
注意:为什么要压缩?当key非常多时,value的类型又都是hash,此时占用的内存就会很大(键值对存储本身就是hash,再套hash,就又复杂占用内存又多)。为了节省内存,就需要进行压缩。
当hash中元素个数比较少(少于hash-max-ziplist-entries配置(redis配置文件中,默认512个))或value比较短(小于hash-max-ziplist-value配置(redis配置文件中,默认64字节))使用ziplist。当元素比较多或value长时,ziplist的读写就会比较慢(因为要反复压缩和解压),此时redis就会使用hashtable来实现hash。
(3)list的内部编码实现有2种:
linkedlist就是链表,适用存大量数据。
ziplist是压缩列表,适用存少量数据。
注意:从Redis 3.2开始引入了quicklist来实现list,不再使用linkedlist和ziplist。quicklist是linkedlist和ziplist的结合,即本身是linkedlist,链表的每个节点是ziplist,这样就既节省了空间,又可以存较多的数据。可以通过list-max-ziplist-size的配置项在redis配置文件中设置ziplist的最大容量。
(4)set的内部实现有2种:
hashtable是哈希表的实现。
intset是整数集合,集合中存储的是整数时使用该编码实现,并且元素个数不多(节省空间)。
(5)zset的内部实现有2种:
skiplist是跳表,也是链表,但是每个节点的指针域不只包含下一个节点的地址,还有其他节点的地址。通过搭配指针域的指向,可以优化查询复杂度为O(logN)。适用于元素个数较多或单个元素的体积较大。
ziplist是压缩列表,适用于元素个数较少或单个元素的体积较小。
2 object encoding
命令:object encoding key。根据key查询对应value的编码方式。
下篇文章: