在上一篇已经说到了,redis的五种对外的数据类型,也就是用户可以选择存储的数据类型。分别是:
string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)
但是如果面对这个问题,仅仅只回答这五种数据类型,显然是不够的。这个问题的本质还是在考验你是否对于redis的每一种数据类型都足够了解,因为只有你深入了解了这些数据类型的结构和redis对它的实现,你才可以在很多场景下清楚的知道你要如何优化你的redis服务。
在redis的内部,上述的五种数据结构都至少有两种以上的内部编码实现,同一种数据结构,实现的编码不同,查询的速度和消耗的内存大小是不同的。所以,了解redis五种类型的内部数据结构实现,就能更好的权衡实际生产场景中应该如何存储你的数据,以达到你想要的优化效果。或是快速的存储,或是想要更有效的利用内存节约资源成本。
下面是redis的五种数据结构所有的内部编码,如图:
你可以通过 object encoding key
命令来查询一个key在redis内部的实现编码。
字符串
字符串对象是Redis内部最常用的数据类型。所有的键都是字符串类型,值对象数据除了整数之外都使用字符串存储。
在redis内部字符串类型的内部编码有3种:
int:8个字节的长整型
embstr:小于等于39个字节的字符串
raw:大于39个字节的字符串
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。查看redis字符串实现详细讲解。
表与集合
redis的表和集合有许多相同的编码实现,下面我全部列出来。
ziplist : 压缩列表
hashtable : 哈希表
linkedlist: 链表
intset : 整数集合
skiplist : 跳跃表
关于这五种数据结构的实现可以看下面这几篇文章:
redis中ziplist实现详细讲解(目前还未写完)
redis中hashtable实现详细讲解(目前还未写完)
redis中linkedlist实现详细讲解(目前还未写完)
redis中intset实现详细讲解(目前还未写完)
redis中skiplist实现详细讲解(目前还未写完)
下面我们来看这些数据结构都有些什么优势。
ziplist:ziplist编码设计出来的主要目的是为了节约内存。它的所有数据都是采用线性连续的内存结构,它redis内应用范围最广的一种编码,可以分别作为hash,ist,zset类型的底层数据结构实现。
优点:内存消耗小。
缺点:查询数据的时间复杂度高O(n)。
hashtable:hashtable是hash表实现源码之一,hash表有很快的查询速度O(1),但是由于没有压缩数据,消耗的内存远远大于ziplist编码。
优点:查询速度极快。
缺点:消耗更多的内存。
linkedlist:linkedlist是list列表的实现源码之一,它是一个双向链表,每个节点还存储了前驱节点和后继节点的地址指针。链表的优势在于插入的时间复杂度是O(1),虽然随机访问的时间复杂度是O(n),但是redis的list结构不需要随机访问,固定的从列表头提取数据,所以速度很快。同样的,它比ziplist消耗的内存更多。 优点:插入速度极快。
缺点:消耗更多的内存。
intset: intset编码是set实现编码的一种,intset编码的特点是有序的存储了不重复的整数类型。
优点:由于是有序集合,集合内查找特定的元素使用二分查找只需要log(n)的时间复杂度。
缺点:只能存储整型元素,而且插入的时候会对元素进行排序,时间复杂度O(n)。
skiplist :skiplist编码是zset有序列表实现编码的一种,skiplist底层由hash表加上跳跃表来实现。主要的思路是用跳跃表插入和查询的时间复杂度都很快(具体取决于每级索引间隔的数据量),而且跳跃表的区间查询的速度也是极快的。缺点依旧是相比ziplist来说,内存消耗大的多。
优点:查询速度快。
缺点:内存消耗多。
介绍完了redis内部的五种数据结构,那么这些结构的优点缺点就一目了然。redis可以通过配置来控制内部编码的实现。也就是说,你可以通过配置控制你的数据的内部存储结构,以达到你想要的效果。
如果你的业务是非I/O密集型,意味着查询速度并不会很影响你的业务。所以你可能更加关注redis的内存消耗,希望你存储的数据消耗更少的内存以降低内存成本。那么你应该更多的使用ziplist来存储你的数据(redis是内存存取,虽然相对其他数据结构查询较慢,但是相对硬件存取的速度也是很快的)。
反过来,如果你的业务是高并发的业务,需要极速响应,很在乎查询的时间,那么你就不应当用ziplist存储你的数据。使用更大的内存来换取查询的速度,使你的业务更加流畅。
下面是关于ziplist的配置:
在redis-cli中使用 set 参数名 数量
命令,就可以配置相应的参数。
需要注意的是,ziplist可以向更复杂的数据内心转换,但是不支持回退到ziplist类型。因为数据增删频繁的时候,数据压缩非常的小号CPU资源,得不偿失。
所以如果已经存储的数据,如果想要以ziplist存储,需要修改配置之后,重新存储一遍才行。