redis的zset的底层实现_Redis5种基本数据结构底层实现

本文大部分知识整理自网上,在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。

前言

本文主要介绍关于Redis的五种基本数据结构的底层实现原理,然后来分析我们常用的使用场景。先简单回顾一下知识点。

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs和 地理空间(geospatial) 索引半径查询。

简单来说,Redis的数据结构主要分为五种基本的数据结构+三种高级的数据结构。我们下面所要介绍的就是这五种基本的数据结构的相关知识。

结构模型介绍

在我们基本的数据结构中,它又有自己的内部编码。

总结一下

(1)每种数据结构都有自己底层的内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码。

(2)可以看到每种数据结构都有两种以上的内部编码实现,例如string数据结构就包含了raw、int和embstr三种内部编码。

(3)同时,有些内部编码可以作为多种外部数据结构的内部实现,例如ziplist就是hash、list和zset共有的内部编码。

结构模型基础

我们在上面了解到了关于键的基本数据结构。而我们Redis中的所有value都是以object的形式存在的。其通用结构结构源码如下:

typedef struct redisObject {

unsigned [type] 4;

unsigned [encoding] 4;

unsigned [lru] REDIS_LRU_BITS;

int refcount;

void *ptr;

} robj;

(1)type指的就是我们的基本数据结构,如string,list等其他类型;

(2)encoding指的是这些结构内部类型的具体实现方式,如string可以用int来实现也可以用char[]来实现;list可以用ziplist或者链表来实现;

(3)lru表示本对象的空转时长,用于有限内存下长时间不访问的对象清理;

(4)refcount对象引用计数,用于GC;

(5)ptr指向以encoding方式实现这个对象实际实现者的地址,如String对象对应的SDS(Simple Dynamic String 结构)地址。

示意图如下:

String类型

关于string内部结构,上面也介绍了主要是以三种编码形式来组成的,分别是int,raw,embstr。这里int主要是用来存放整形值的字符串,embstr用来存放字符串的短字符串(大小不超过44个字节),raw存放字符的长字符串(大小不超过44个字节)。

SDS结构

我们在上面介绍了关于键的基本结构redisObject,但其实在我们的String中还用着另外一种结构,也就是我们的SDS结构(Simple Dynamic String 结构)。

从源码的文件里面可以看见,同样一组结构Redis使用泛型定义了好多次。那么为什么不直接用int类型呢?这里呢主要是因为当字符串比较短的时候,len和alloc可以使用byte和short来表示,Redis为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示。

为什么不直接使用C字符串呢?

我们为什么要重新在定义一个SDS的动态字符串的结构?其实呢这主要是为了从Redis对字符串安全性和效率以及功能方面的要求。C 语言使用了一个长度为 N+1 的字符数组来表示长度为 N 的字符串,并且字符数组最后一个元素总是 '\0'。而在Redis中\0可能会被判定为提前结束而识别不了字符串。通过分析可以发现,总共有以下一些缺点:

(1)获取字符串长度为O(n),因为C字符串需要去遍历。

(2)不能很好的杜绝缓冲区溢出/内存泄漏的问题,因为原因同上,进行字符串拼接等其他操作获取长度的时候易出现问题。

(3)C字符串只能保存文本数据,因为必须符合某种编码(如ASCLL)。像一些\0就不易处理。

表格区别汇总如下。

C字符串

SDS

获取字符串长度的复杂度为O(N)

获取字符串长度的复杂度为O(1)

API是不安全的,可能会造成缓冲区溢出

API是安全的,不会造成缓冲区溢出

修改字符串长度N次必然需要执行N次内存重分配

修改字符串长度N次最多需要执行N次内存重分配

只能保存文本数据

可以保存文本或者二进制数据

可以使用所有库中的函数

可以使用一部分库中的函数

raw与embstr的区别

(1)redis并未提供任何修改embstr的方式,即embstr是只读的形式。对embstr的修改实际上是先转换为raw再进行修改。

(2)采用内存分配方式不同,虽然raw和embstr编码方式都是使用redisObject结构和sdshdr结构。但是raw编码方式采用两次分配内存的方式,分别创建redisObject和sdshdr,而emb

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值