加入收藏 | 设为首页 | 会员中心 | 我要投稿 河北网 (https://www.hebeiwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

Redis基本类型及其数据结构

发布时间:2019-09-02 20:24:53 所属栏目:建站 来源:xy的技术圈
导读:早年在行使Redis的时辰,只是简朴地行使它提供的根基数据范例和接口,并没有深入研究它底层的数据布局。最近规划从头进修梳理一下Redis方面的常识,以是规划从先容Redis的根基范例及其数据布局入手。 redisObject Redis的key是顶层模子,它的value是扁平化
副问题[/!--empirenews.page--]

早年在行使Redis的时辰,只是简朴地行使它提供的根基数据范例和接口,并没有深入研究它底层的数据布局。最近规划从头进修梳理一下Redis方面的常识,以是规划从先容Redis的根基范例及其数据布局入手。

Redis根基范例及其数据布局

redisObject

Redis的key是顶层模子,它的value是扁平化的。Redis中,全部的value都是一个object,它的布局如下:

  1. typedef struct redisObject { 
  2.  unsigned [type] 4; 
  3.  unsigned [encoding] 4; 
  4.  unsigned [lru] REDIS_LRU_BITS; 
  5.  int refcount; 
  6.  void *ptr; 
  7. } robj; 

简朴先容一下这几个字段:

  • type:数据范例,就是我们认识的string、hash、list等。
  • encoding:内部编码,着实就是本文要先容的数据布局。指的是当前这个value底层是用的什么数据布局。由于统一个数据范例底层也有多种数据布局的实现,以是这里必要指定命据布局。
  • REDIS_LRU_BITS:当前工具可以保存的时长。这个我们在后头讲键的逾期计策的时辰讲。
  • refcount:工具引用计数,用于GC。
  • ptr:指针,指向以encoding的方法实现这个工具的现实地点。
Redis根基范例及其数据布局

string

在Redis内部,string范例有两种底层储存布局。Redis会按照存储的数据及用户的操纵指令自动选择吻合的布局:

  • int:存放整数范例;
  • SDS:存放浮点、字符串、字节范例;
  1. SDS: 简朴动态字符串 simple dynamic string 

SDS

SDS的内部数据布局:

  1. typedef struct sdshdr { 
  2.  // buf中已经占用的字符长度 
  3.  unsigned int len; 
  4.  // buf中剩余可用的字符长度 
  5.  unsigned int free; 
  6.  // 数据空间 
  7.  char buf[]; 

可见,其底层是一个char数组。buf最大容量为512M,内里可以放字符串、浮点数和字节。以是你乃至可以放一张序列化后的图片。它为什么没有直接行使数组,而是包装成了这样的数据布局呢?

由于buf会有动态扩容和缩容的需求。假如直接行使数组,那每次对字符串的修改城市导致从头分派内存,服从很低。

buf的扩容进程如下:

  • 假如修改后len长度将小于1M,这时分派给free的巨细和len一样,譬喻修改事后为10字节, 那么给free也是10字节,buf现实长度酿成了10 + 10 + 1 = 21byte
  • 假如修改后len长度将大于便是1M,这时分派给free的长度为1M,譬喻修改事后为30M,那么给free是1M.buf现实长度酿成了30M + 1M + 1byte 
Redis根基范例及其数据布局

惰性空间开释指的是当字符串收缩时,并没有真正的缩容,而是移动free的指针。这样未来字符串长度增进时,就不消从头分派内存了。但这样会造成内存挥霍,Redis提供了API来真正开释内存。

list

list底层有两种数据布局:链表linkedlist和压缩列表ziplist。当list元素个数少且元素内容长度不大时,行使ziplist实现,不然行使linkedlist。

链表

Redis行使的链表是双向链表。为了利便操纵,行使了一个list布局来持有这个链表。如图所示:

Redis根基范例及其数据布局
  1. typedef struct list{ 
  2.  //表头节点 
  3.  listNode *head; 
  4.  //表尾节点 
  5.  listNode *tail; 
  6.  //链表所包括的节点数目 
  7.  unsigned long len; 
  8.  //节点值复制函数 
  9.  void *(*dup)(void *ptr); 
  10.  //节点值开释函数 
  11.  void *(*free)(void *ptr); 
  12.  //节点值比拟函数 
  13.  int (*match)(void *ptr,void *key); 
  14. }list; 

data存的着实也是一个指针。链表内里的元素是上面先容的string。由于是双向链表,以是可以很利便地把它当成一个栈可能行列来行使。

压缩列表

与上面的链表相对应,压缩列表有点儿相同数组,通过一片持续的内存空间,来存储数据。不外,它跟数组差异的一点是,它应承存储的数据巨细差异。每个节点上增进一个length属性来记录这个节点的长度,这样较量利便地获得下一个节点的位置。

Redis根基范例及其数据布局

上图的各字段寄义为:

  • zlbytes:列表的总长度
  • zltail:指向最末元素
  • zllen:元素的个数
  • entry:元素的内容,内里记录了前一个Entry的长度,用于利便双向遍历
  • zlend:恒为0xFF,作为ziplist的定界符

压缩列表不可是list的底层实现,也是hash的底层实现之一。当hash的元素个数少且内容长度不大时,行使压缩列表来实现。

hash

hash底层有两种实现:压缩列表和字典(dict)。压缩列表方才上面已经先容过了,下面首要先容一下字典的数据布局。

字典

(编辑:河北网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读