redis数据类型(5种)和底层实现
下面我们就学习Redis的数据结构,也是使用Redis要知道的最基础的知识。Redis是一个Key-Value型的内存数据库,它所有的key都是字符串,而value常见的数据类型有五种:string,list,set,zset,hash。Redis的这些数据结构,在底层都是使用redisObject来进行表示。redisObject中有三个重要的属性,分别是。表示保存的value的类型。。常用的命
redis数据类型(5种)和底层实现
Redis的特点
要用好Redis,首先要明白它的特点:
- 读写速度快。redis官网测试读写能到10万左右每秒。速度快的原因这里简单说一下,第一是因为数据存储在内存中,我们知道机器访问内存的速度是远远大于访问磁盘的,其次是Redis采用单线程的架构,避免了上下文的切换和多线程带来的竞争,也就不存在加锁释放锁的操作,减少了CPU的消耗,第三点是采用了非阻塞IO多路复用机制。
- 数据结构丰富。 Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构。这也是这篇文章要讲的。
- 支持持久化。Redis提供了RDB和AOF两种持久化策略,能最大限度地保证Redis服务器宕机重启后数据不会丢失。
- 支持高可用。可以使用主从复制,并且提供哨兵机制,保证服务器的高可用。
- 客户端语言多。因为Redis受到社区和各大公司的广泛认可,所以客户端语言涵盖了所有的主流编程语言,比如Java,C,C++,PHP,NodeJS等等。
Redis的数据结构
下面我们就学习Redis的数据结构,也是使用Redis要知道的最基础的知识。
Redis是一个Key-Value型的内存数据库,它所有的key都是字符串,而value常见的数据类型有五种:string,list,set,zset,hash。
Redis的这些数据结构,在底层都是使用redisObject来进行表示。redisObject中有三个重要的属性,分别是type、 encoding 和 ptr。
type表示保存的value的类型。通常有以下几种,也就是常见的五种数据结构:
- 字符串 REDIS_STRING
- 列表 REDIS_LIST
- 集合 REDIS_SET
- 有序集合 REDIS_ZSET
- 字典 REDIS_HASH
string(字符串)
这是redis中最常用的数据类型,字符串对象的 encoding 有三种,分别是:int、raw、embstr。
常用的命令有常用命令: set、get、decr、incr、mget 等。
我们知道Redis是用C语言开发的,但是底层存储不是使用C语言的字符串类型,而是自己开发了一种数据类型SDS进行存储,SDS即Simple Dynamic String ,是一种动态字符串。
hash(字典)
哈希对象的编码有两种,分别是:ziplist、hashtable。
当哈希对象保存的键值对数量小于 512,并且所有键值对的长度都小于 64 字节时,使用ziplist(压缩列表)存储;否则使用 hashtable 存储。
Redis中的hashtable跟Java中的HashMap类似,都是通过"数组+链表"的实现方式解决部分的哈希冲突。
list(链表)
列表对象的编码有两种,分别是:ziplist、linkedlist。当列表的长度小于 512,并且所有元素的长度都小于 64 字节时,使用ziplist存储;否则使用 linkedlist 存储。
Redis中的linkedlist类似于Java中的LinkedList,是一个链表,底层的实现原理也和LinkedList类似。这意味着list的插入和删除操作效率会比较快,时间复杂度是O(1)。
set(集合)
set类型的特点很简单,无序,不重复,跟Java的HashSet类似。它的编码有两种,分别是intset和hashtable。如果value可以转成整数值,并且长度不超过512的话就使用intset存储,否则采用hashtable。
hashtable在前面讲hash类型时已经讲过,这里的set集合采用的hashtable几乎一样,只是哈希表的value都是NULL。这个不难理解,比如用Java中的HashMap实现一个HashSet,我们只用HashMap的key就是了。
zset(有序集合)
zset是Redis中比较有特色的数据类型,它和set一样是不可重复的,区别在于多了score值,用来代表排序的权重。也就是当你需要一个有序的,不可重复的集合列表时,就可以考虑使用这种数据类型。
zset的编码有两种,分别是:ziplist、skiplist。当zset的长度小于 128,并且所有元素的长度都小于 64 字节时,使用ziplist存储;否则使用 skiplist 存储。
这里要讲一下skiplist,也就是跳跃表。它的底层实现比较复杂,这里简单地提一下。
跳表是在双向链表之上加多层索引构成的,相对于双向链表,支持快速查找,更新,删除,所以适用于需求灵活的场景。
查找某一个数据时,先在索引里面查找出一个大的范围,然后再下降到原始链表中精确查找。
因为加一层索引后,查找一个结点需要遍历的次数减少了,所以查找效率大大提升。【空间换时间】
针对链表长度比较大的时候,构建索引查找效率的提升就会非常明显。
跳表的特点
(1) 跳表结合了链表和类似二分查找的思想;
(2) 有很多层结构,由原始链表和一些通过“跳跃”生成的链表组成;
(3) 每一层都是一个有序的链表;
(4) 最底层(Level 1)的链表包含所有元素,越上层“跳跃”的越高,元素(索引)越少;
(5) 查找时从顶层向下,不断缩小搜索范围;
(6) 上层链表是下层链表的子序列;
(7) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。
跳表的搜索
现在访问节点7 经过的节点为1->6->7
链表是有序的,但不能使用二分查找("类似"二分法)。类似二叉搜索树,我们把一些结点提取出来,作为索引。在实际开发中,原始链表中存储的可能是很大的对象,而索引结点只需要存储关键值和几个指针,其额外占用的空间可以被忽略掉。
类似"二分法)。类似二叉搜索树,我们把一些结点提取出来,作为索引。在实际开发中,原始链表中存储的可能是很大的对象,而索引结点只需要存储关键值和几个指针,其额外占用的空间可以被忽略掉。
注意:每隔两个节点往上提升一层建立索引只是理想情况,实际上是通过随机层数K(丢硬币决定 K,随机算法)来实现。
更多推荐
所有评论(0)