redis中ziplist,skiplist

  • ziplist压缩表

ziplist主要是为了节约内存,他将元素存储在一块连续的内存空间中,这样在查询数据的时候也可以利用CPU的缓存访问数据,加快查询的效率

相较于数组而言。我们知道,数组要求每个元素的大小都相同,如果我们要存储不同长度的字符串,那我们就需要用最大长度的字符串大小作为元素的大小(假设是5个字节)。小于5个字节长度的字符串也会开辟5个字节,便会浪费部分存储空间,

ziplist就是根据每个节点的长度来决定占用内存大小,这样每次添加元素时就可以计算下一个节点在内存中的存储位置,从而形成一个压缩列表。

ziplist在redis中的使用

// 压缩列表 struct ziplist<T> { int32 zlbytes; // 压缩列表占用的内存字节数 int32 zltail_offset; // 记录表尾节点距离起始地址有多少个字节,用于快速定位最后一个元素 int16 zllength; // 压缩列表包含的节点数 T[] entries; // 压缩列表包含的所有节点 int8 zlend; // 特殊值0xFF,标记压缩列表结尾 } ziplist;

zlentry节点的组成

// 列表节点 struct entry { int<val> prevlen; // 前一个entry节点的长度,便于反向查找 int<val> encoding; // 节点的content属性保存的数据的类型 optional byte[] content; // 节点的值 } entry;

通过content的字节大小,可以定位下一个节点的位置,便于ziplist链表的遍历

  • skiplist跳表

跳表(skip list) 对标的是平衡树(AVL Tree),红黑树,是一种 插入/删除/搜索 都是 O(log n) 的数据结构。这两个查询效率差不多,

  • 跳表它最大的优势是原理简单、容易实现、效率更高。
  • 在并发的情况下,红黑树在插入删除的时候可能需要做数的平衡的操作,即树的左旋和右旋来保证树的平衡,会影响其他部分树的节点,而跳表只会影响局部,不会影响其他的节点

skiplist以空间换时间

跳表处理的是有序的链表(一般是双向链表),最底层就是原始数据双向链表(按照score分数从小到大排序),其他每个节点都有一个层数level[],每个层都有一个索引节点,主要为了加快查询数据的速度

skiplist的底层数据结构

typedef struct zskiplist { // 头节点,尾节点 struct zskiplistNode *header, *tail; // 节点数量 unsigned long length; // 目前表内节点的最大层数 int level; } zskiplist; typedef struct zskiplistNode { // member 对象 robj *obj; // 分值,底层是原始数据,双向链表为按照score从小到大进行排序 double score; // 后退指针 struct zskiplistNode *backward; // 层,节点创建会根据随机算法,计算出层数,就是lecel数组的大小 struct zskiplistLevel { // 前进指针,指向下一个节点 struct zskiplistNode *forward; // 这个层跨越的节点数量,在同一层中当前节点到下一个节点的距离 unsigned int span; } level[]; } zskiplistNode;

如果没有level层,即索引,查询链表时会从头到尾的遍历链表,这个查询就会比较慢

所以跳表就必须加层,加索引,提高查询效率

跳表是牺牲空间来换取时间,除了最底层是最原始的数据外(双向链表),其他的每一层,其实都相当于是一个索引(单向链表),

当查询数据的时候会从最高层,开始level3开始检索,例如搜索117,从level3开始检索,21117,就转向level2 37节点开始继续向前检索,直到找到检索的元素,(这样一层层的检索主要是因为,底层原始数据是有序的双向链表,所以每层索引节点单向链表也是有序的),

这样可以一次跳过多个节点

检索数据19,查询执行图

插入元素到跳表,一个节点要不要被索引,建几层的索引,都在节点插入时通过随机算法计算出来的,也就是层数level[]是随机的,最终会将元素插入到最底层原始数据(双向链表)中去,层数随机计算,之后每一层都会添加索引节点

119添加的节点层数level会按照随机算法进行计算得到

新添加的节点119,他的forward前进指针会指向当前层的最右边的节点,span会计算当前层当前节点和最右边节点的距离,并且119节点最左边的节点85和层节点71的forward,和span都会重新计算,

记住需要理解跳表好处,主要提高检索效率,查询接近二分查找,

例如面试官问题你,为何redis这么快,不要在说一些八股文了,

1,可以从数据结构上跟面试官分析,为什么redis五大基本数据类型,查询性能为这么高,

2,IO多路复用机制,请看后面的文章,

如果能从原理上分析,才能真真的明白redis为何这么快,redis6.0加入多线程,主要在网络IO上,

如果能输出redis的IO模型,你就很好了,

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值