请选择 进入手机版 | 继续访问电脑版

[Redis] Redis底层数据布局 详解

[复制链接]
查看43 | 回复9 | 2021-9-14 00:15:21 | 显示全部楼层 |阅读模式

Redis作为Key-Value存储体系 ,数据布局 如下:

在这里插入图片形貌

Redis没有表的概念,Redis实例所对应的db以编号区分,db本身就是key的定名 空间。

比如:user:1000作为key值,表示在user这个定名 空间下id为1000的元素,雷同 于user表的id=1000的行。

RedisDB布局

Redis中存在“数据库”的概念,该布局 由redis.h中的redisDb定义。

当redis 服务器初始化时,会预先分配 16 个数据库

全部 数据库保存到布局 redisServer 的一个成员 redisServer.db 数组中

redisClient中存在一个名叫db的指针指向当前利用 的数据库

RedisDB布局 体源码:

  1. /* Redis database representation. There are multiple databases identified
  2. * by integers from 0 (the default database) up to the max configured
  3. * database. The database number is the 'id' field in the structure. */
  4. typedef struct redisDb {
  5. dict *dict; /* 存储数据库所有的key-value */
  6. dict *expires; /* 存储key的过期时间 */
  7. dict *blocking_keys; /* blpop 存储阻塞key和客户端对象*/
  8. dict *ready_keys; /* 阻塞后push 响应阻塞客户端 存储阻塞后push的key和客户端对象 */
  9. dict *watched_keys; /* 存储watch监控的的key和客户端对象 */
  10. int id; /* Database ID */
  11. long long avg_ttl; /* 存储的数据库对象的平均ttl(time to live),用于统计 */
  12. unsigned long expires_cursor; /* 循环过期检查的光标. */
  13. list *defrag_later; /* 需要尝试去清理磁盘碎片的链表,会慢慢的清理 */
  14. } redisDb;
复制代码

id
id是数据库序号,为0-15(默认Redis有16个数据库)

dict
存储数据库全部 的key-value,后面要具体 讲解

expires
存储key的过期时间,后面要具体 讲解

RedisObject布局

Value是一个对象
包含字符串对象,列表对象,哈希对象,集合对象和有序集合对象

布局 信息概览

  1. typedef struct redisObject {
  2. unsigned type:4; //类型 对象类型
  3. unsigned encoding:4;//编码
  4. // LRU_BITS为24bit 记录最后一次被命令程序访问的时间
  5. unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
  6. * LFU data (least significant 8 bits frequency
  7. * and most significant 16 bits access time). */
  8. int refcount; //引用计数
  9. void *ptr;//指向底层实现数据结构的指针
  10. } robj;
复制代码

4位type

type 字段表示对象的范例 ,占 4 位;

REDIS_STRING(字符串)、REDIS_LIST (列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有序集合)。

当我们实行 type 下令 时,便是通过读取 RedisObject 的 type 字段获得对象的范例

  1. 127.0.0.1:6379> set a1 111
  2. OK
  3. 127.0.0.1:6379> type a1
  4. string
复制代码

4位encoding

encoding 表示对象的内部编码,占 4 位

每个对象有不同的实现编码

Redis 可以根据不同的利用 场景来为对象设置不同的编码,大大进步 了 Redis 的机动 性和服从 。

通过 object encoding 下令 ,可以查看对象采用的编码方式

  1. 127.0.0.1:6379> OBJECT encoding a1
  2. "int"
复制代码

24位LRU
lru 记录的是对象末了 一次被下令 程序访问的时间,( 4.0 版本占 24 位,2.6 版本占 22 位)。

高16位存储一个分钟数级别的时间戳,低8位存储访问计数(lfu : 迩来 访问次数)

   lru----> 高16位: 末了 被访问的时间

   lfu----->低8位:迩来 访问次数

refcount
refcount 记录的是该对象被引用的次数,范例 为整型。

refcount 的作用,告急 在于对象的引用计数和内存回收。

当对象的refcount>1时,称为共享对象

Redis 为了节流 内存,当有一些对象重复出现时,新的程序不会创建新的对象,而是仍然 利用 原来的对象。

ptr
ptr 指针指向具体 的数据,比如:set hello world,ptr 指向包含字符串 world 的 SDS。

7种type 字符串对象

C语言: 字符数组 “\0”

Redis 利用 了 SDS(Simple Dynamic String)。用于存储字符串和整型数据。

在这里插入图片形貌

  1. /* Note: sdshdr5 is never used, we just access the flags byte directly.
  2. * However is here to document the layout of type 5 SDS strings. */
  3. struct __attribute__ ((__packed__)) sdshdr5 {
  4. unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
  5. char buf[];
  6. };
  7. struct __attribute__ ((__packed__)) sdshdr8 {
  8. uint8_t len; /* used */
  9. uint8_t alloc; /* excluding the header and null terminator */
  10. unsigned char flags; /* 3 lsb of type, 5 unused bits */
  11. char buf[];
  12. };
  13. struct __attribute__ ((__packed__)) sdshdr16 {
  14. uint16_t len; /* used */
  15. uint16_t alloc; /* excluding the header and null terminator */
  16. unsigned char flags; /* 3 lsb of type, 5 unused bits */
  17. char buf[];
  18. };
  19. struct __attribute__ ((__packed__)) sdshdr32 {
  20. uint32_t len; /* used */
  21. uint32_t alloc; /* excluding the header and null terminator */
  22. unsigned char flags; /* 3 lsb of type, 5 unused bits */
  23. char buf[];
  24. };
  25. struct __attribute__ ((__packed__)) sdshdr64 {
  26. uint64_t len; /* used */
  27. uint64_t alloc; /* excluding the header and null terminator */
  28. unsigned char flags; /* 3 lsb of type, 5 unused bits */
  29. char buf[];
  30. };
复制代码

buf[] 的长度=len+free+1

SDS的上风 :

1.SDS 在 C 字符串的基础上加入了 free 和 len 字段,获取字符串长度:SDS 是 O(1),C 字符串是
O(n)。
buf数组的长度=free+len+1

2.SDS 由于记录了长度,在大概 造成缓冲区溢出时会自动 重新分配内存,杜绝了缓冲区溢出。

3.可以存取二进制数据,以字符串长度len来作为竣事 标识

  • C:

\0 空字符串 二进制数据包括空字符串,以是 没有办法存取二进制数据

  • SDS :

非二进制 \0
二进制: 字符串长度 可以存二进制数据

利用 场景:
SDS的告急 应用在:存储字符串和整型数据、存储key、AOF缓冲区和用户输入缓冲。

跳跃表(告急 )

跳跃表是有序集合(sorted-set)的底层实现,服从 高,实现简单。

跳跃表的基本头脑 :

将有序链表中的部分节点分层,每一层都是一个有序链表。

查找

在查找时优先从最高层开始向后查找,当到达某个节点时,假如 next节点值大于要查找的值或next指针指向null,则从当前节点降落 一层继续向后查找。

举例:

在这里插入图片形貌

查找元素9,按道理我们必要 从头结点开始遍历,一共遍历8个结点才能找到元素9。

第一次分层:

遍历5次找到元素9(红色的线为查找路径)

在这里插入图片形貌

第二次分层:

遍历4次找到元素9

在这里插入图片形貌

第三层分层:

遍历4次找到元素9

在这里插入图片形貌

这种数据布局 ,就是跳跃表,它具有二分查找的功能。

插入与删除

上面例子中,9个结点,一共4层,是抱负 的跳跃表。

通过抛硬币(概率1/2)的方式来决定新插入结点超过 的层数,每层都必要 判断 :

正面:插入上层

背面:不插入

达到1/2概率(计算次数)

删除

找到指定元素并删除每层的该元素即可

跳跃表特点:

每层都是一个有序链表

查找次数近似于层数(1/2)

底层包含全部 元素

空间复杂度 O(n) 扩充了一倍

Redis跳跃表的实现

  1. /* ZSETs use a specialized version of Skiplists */
  2. typedef struct zskiplistNode {
  3. /* 存储字符串类型数据 redis3.0版本中使用robj类型表示,但是在redis4.0.1中直接使用sds类型表示 */
  4. sds ele;
  5. /*存储排序的分值*/
  6. double score;
  7. /*后退指针,指向当前节点最底层的前一个节点*/
  8. struct zskiplistNode *backward;
  9. /*层,柔性数组,随机生成1-64的值*/
  10. struct zskidictEntryplistLevel {
  11. struct zskiplistNode *forward; //指向本层下一个节点
  12. unsigned long span; //本层下个节点到本节点的元素个数
  13. } level[];
  14. } zskiplistNode;
  15. typedef struct zskiplist {
  16. //表头节点和表尾节点
  17. struct zskiplistNode *header, *tail;
  18. //表中节点的数量
  19. unsigned long length;
  20. //表中层数最大的节点的层数
  21. int level;
  22. } zskiplist;
复制代码

完备 的跳跃表布局 体:

在这里插入图片形貌

跳跃表的上风 :
1、可以快速查找到必要 的节点 O(logn)
2、可以在O(1)的时间复杂度下,快速获得跳跃表的头节点、尾结点、长度和高度。
应用场景:有序集合的实现

字典(告急 )

字典dict又称散列表(hash),是用来存储键值对的一种数据布局 。
Redis整个数据库是用字典来存储的。(K-V布局 )
对Redis举行 CURD操作实在 就是对字典中的数据举行 CURD操作。

数组

数组:用来存储数据的容器,采用头指针+偏移量的方式可以或许 以O(1)的时间复杂度定位到数据地点 的内存地址。

Redis 海量存储 快

Hash函数

Hash(散列),作用是把恣意 长度的输入通过散列算法转换成固定范例 、固定长度的散列值。

hash函数可以把Redis里的key:包括字符串、整数、浮点数同一 转换成整数。

key=100.1 String “100.1” 5位长度的字符串

Redis-cli :times 33

Redis-Server : MurmurHash

数组下标=hash(key)%数组容量(hash值%数组容量得到的余数)

Hash冲突

不同的key颠末 计算后出现数组下标同等 ,称为Hash冲突。

采用单链表在雷同 的下标位置处存储原始key和value

当根据key找Value时,找到数组下标,遍历单链表可以找出key雷同 的value

在这里插入图片形貌

Redis字典的实现

Redis字典实现包括:字典(dict)、Hash表(dictht)、Hash表节点(dictEntry)。

在这里插入图片形貌

Hash表

  1. typedef struct dictht {
  2. dictEntry **table; // 哈希表数组
  3. unsigned long size; // 哈希表数组的大小
  4. unsigned long sizemask; // 用于映射位置的掩码,值永远等于(size-1)
  5. unsigned long used; // 哈希表已有节点的数量,包含next单链表数据
  6. } dictht;
复制代码

1、hash表的数组初始容量为4,随着k-v存储量的增长 必要 对hash表数组举行 扩容,新扩容量为当前量的一倍,即4,8,16,32

2、索引值=Hash值&掩码值(Hash值与Hash表容量取余)

Hash表节点

  1. typedef struct dictEntry {
  2. void *key; // 键
  3. union { // 值v的类型可以是以下4种类型
  4. void *val;
  5. uint64_t u64;
  6. int64_t s64;
  7. double d;
  8. } v;
  9. struct dictEntry *next; // 指向下一个哈希表节点,形成单向链表 解决hash冲突, 单链表中会存储key和value
  10. } dictEntry;
复制代码

key字段存储的是键值对中的键

v字段是个连合 体,存储的是键值对中的值。

next指向下一个哈希表节点,用于办理 hash冲突

在这里插入图片形貌

dict字典

  1. typedef struct dict {
  2. dictType *type; //该字典对应的特定操作函数
  3. void *privdata; //上述类型函数对应的可选参数
  4. dictht ht[2];/* 两张哈希表,存储键值对数据,ht[0]为原生哈希表,ht[1]为 rehash 哈希表 */
  5. long rehashidx; /* rehash标识 当等于-1时表示没有在rehash,否则表示正在进行rehash操作,
  6. 存储的值表示hash表 ht[0]的rehash进行到哪个索引值(数组下标)*/
  7. unsigned long iterators; /* 当前运行的迭代器数量 */
  8. } dict;
复制代码

type字段,指向dictType布局 体,里边包括了对该字典操作的函数指针

  1. typedef struct dictType {
  2. // 计算哈希值的函数
  3. uint64_t (*hashFunction)(const void *key);
  4. // 复制键的函数
  5. void *(*keyDup)(void *privdata, const void *key);
  6. // 比较键的函数
  7. void *(*valDup)(void *privdata, const void *obj);
  8. // 比较键的函数
  9. int (*keyCompare)(void *privdata, const void *key1, const void *key2);
  10. // 销毁键的函数
  11. void (*keyDestructor)(void *privdata, void *key);
  12. // 销毁值的函数
  13. void (*valDestructor)(void *privdata, void *obj);
  14. } dictType;
复制代码

  Redis字典除了主数据库的K-V数据存储以外,还可以用于:散列表对象、哨兵模式中的主从节点管理等在不同的应用中,字典的形态都大概 不同,dictType是为了实现各种形态的字典而抽象出来的操作函数(多态)。

完备 的Redis字典数据布局 :

在这里插入图片形貌

字典扩容

字典达到存储上限(阈值 0.75),必要 rehash(扩容)

在这里插入图片形貌

阐明 :

初次申请默认容量为4个dictEntry,非初次申请为当前hash表容量的一倍。rehashidx=0表示要举行 rehash操作。新增长 的数据在新的hash表h[1]修改、删除、查询在老hash表h[0]、新hash表h[1]中(rehash中)将老的hash表h[0]的数据重新计算索引值后全部迁徙 到新的hash表h[1]中,这个过程称为rehash。 渐进式rehash

当数据量巨大时rehash的过程黑白 常缓慢的,以是 必要 举行 优化。
服务器忙,则只对一个节点举行 rehash
服务器闲,可批量rehash(100节点)
应用场景:
1、主数据库的K-V数据存储
2、散列表对象(hash)
3、哨兵模式中的主从节点管理

压缩列表

压缩列表(ziplist)是由一系列特别 编码的一连 内存块构成 的次序 型数据布局

节流 内存
是一个字节数组,可以包含多个节点(entry)。每个节点可以保存一个字节数组或一个整数。

压缩列表的数据布局 如下:

在这里插入图片形貌

zlbytes:压缩列表的字节长度
zltail:压缩列表尾元素相对于压缩列表起始地址的偏移量
zllen:压缩列表的元素个数
entry1…entryX : 压缩列表的各个节点
zlend:压缩列表的末端 ,占一个字节,恒为0xFF(255)
entryX元素的编码布局 :

在这里插入图片形貌

previous_entry_length:前一个元素的字节长度
encoding:表示当前元素的编码
content:数据内容

ziplist布局 体如下:

  1. struct ziplist<T>{
  2. unsigned int zlbytes; // ziplist的长度字节数,包含头部、所有entry和zipend。
  3. unsigned int zloffset; // 从ziplist的头指针到指向最后一个entry的偏移量,用于快速反向查询
  4. unsigned short int zllength; // entry元素个数T[] entry; // 元素值
  5. unsigned char zlend; // ziplist结束符,值固定为0xFF
  6. }
  7. typedef struct zlentry {
  8. unsigned int prevrawlensize; //previous_entry_length字段的长度
  9. unsigned int prevrawlen; //previous_entry_length字段存储的内容
  10. unsigned int lensize; //encoding字段的长度
  11. unsigned int len; //数据内容长度
  12. unsigned int headersize; //当前元素的首部长度,即previous_entry_length字段长度与 encoding字段长度之和。
  13. unsigned char encoding; //数据类型
  14. unsigned char *p; //当前元素首地址
  15. } zlentry;
复制代码

应用场景:
sorted-set和hash元素个数少且是小整数或短字符串(直接利用 )

list用快速链表(quicklist)数据布局 存储,而快速链表是双向列表与压缩列表的组合。(间接利用 )

整数集合

整数集合(intset)是一个有序的(整数升序)、存储整数的一连 存储布局 。
当Redis集合范例 的元素都是整数并且都处在64位有符号整数范围内(-2^63 ~ 2^63 -1 ),利用 该布局 体存储。

  1. 127.0.0.1:6379> SADD set:1 12 6 8
  2. (integer) 3
  3. 127.0.0.1:6379> OBJECT encoding set:1
  4. "intset"
  5. 127.0.0.1:6379> SADD set:2 1 1000000000000000000000000000000000000000000000000000000 99999999999999999999999999999
  6. (integer) 3
  7. 127.0.0.1:6379> OBJECT encoding set:2
  8. "hashtable"
复制代码

intset的布局 图如下:

在这里插入图片形貌

  1. typedef struct intset{
  2. //编码方式
  3. uint32_t encoding;
  4. //集合包含的元素数量
  5. uint32_t length;
  6. //保存元素的数组
  7. int8_t contents[];
  8. }intset;
复制代码

应用场景:
可以保存范例 为int16_t、int32_t 或者int64_t 的整数值,并且保证集合中不会出现重复元素。

快速列表(告急 )

  快速列表(quicklist)是Redis底层告急 的数据布局 。是列表的底层实现。(在Redis3.2之前,Redis采用双向链表(adlist)和压缩列表(ziplist)实现。)在Redis3.2以后联合 adlist和ziplist的上风 Redis计划 出了quicklist。

  1. 127.0.0.1:6379> LPUSH list:001 2 3 5 6 7
  2. (integer) 5
  3. 127.0.0.1:6379> OBJECT encoding list:001
  4. "quicklist"
复制代码

双向列表(adlist)

在这里插入图片形貌

双向链表上风 :

  1. 双向:链表具有前置节点和后置节点的引用,获取这两个节点时间复杂度都为O(1)。
  2. 平凡 链表(单链表):节点类保留下一节点的引用。链表类只保留头节点的引用,只能从头节点插入删除
  3. 无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问都是以 NULL 竣事 。
  4. 环状:头的前一个节点指向尾节点
  5. 带链表长度计数器:通过 len 属性获取链表长度的时间复杂度为 O(1)。
  6. 多态:链表节点利用 void* 指针来保存节点值,可以保存各种不同范例 的值。

快速列表
quicklist是一个双向链表,链表中的每个节点时一个ziplist布局 。quicklist中的每个节点ziplist都可以或许 存储多个数据元素。

在这里插入图片形貌

quicklist的布局 定义如下:

  1. #if UINTPTR_MAX == 0xffffffff
  2. /* 32-bit */
  3. # define QL_FILL_BITS 14
  4. # define QL_COMP_BITS 14
  5. # define QL_BM_BITS 4
  6. #elif UINTPTR_MAX == 0xffffffffffffffff
  7. /* 64-bit */
  8. # define QL_FILL_BITS 16
  9. # define QL_COMP_BITS 16
  10. # define QL_BM_BITS 4 /* we can encode more, but we rather limit the user
  11. since they cause performance degradation. */
  12. #else
  13. # error unknown arch bits count
  14. #endif
  15. /* quicklist is a 40 byte struct (on 64-bit systems) describing a quicklist.
  16. * 'count' is the number of total entries.
  17. * 'len' is the number of quicklist nodes.
  18. * 'compress' is: 0 if compression disabled, otherwise it's the number
  19. * of quicklistNodes to leave uncompressed at ends of quicklist.
  20. * 'fill' is the user-requested (or default) fill factor.
  21. * 'bookmakrs are an optional feature that is used by realloc this struct,
  22. * so that they don't consume memory when not used. */
  23. typedef struct quicklist {
  24. quicklistNode *head; // 指向quicklist的头部
  25. quicklistNode *tail; // 指向quicklist的尾部
  26. unsigned long count; /* 列表中所有数据项的个数总和 */
  27. unsigned long len; /* quicklist节点的个数,即ziplist的个数 */
  28. int fill : QL_FILL_BITS; /* ziplist大小限定,由list-max-ziplist-size给定 (Redis设定)*/
  29. unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
  30. unsigned int bookmark_count: QL_BM_BITS; /*节点压缩深度设置,由list-compress-depth给定*/
  31. quicklistBookmark bookmarks[]; /*可选新特性 使用realloc重新分配空间的时候会用到*/
  32. } quicklist;
复制代码

quicklistNode的布局 定义如下:

  1. /* quicklistNode is a 32 byte struct describing a ziplist for a quicklist.
  2. * We use bit fields keep the quicklistNode at 32 bytes.
  3. * count: 16 bits, max 65536 (max zl bytes is 65k, so max count actually < 32k).
  4. * encoding: 2 bits, RAW=1, LZF=2.
  5. * container: 2 bits, NONE=1, ZIPLIST=2.
  6. * recompress: 1 bit, bool, true if node is temporary decompressed for usage.
  7. * attempted_compress: 1 bit, boolean, used for verifying during testing.
  8. * extra: 10 bits, free for future use; pads out the remainder of 32 bits */
  9. typedef struct quicklistNode {
  10. struct quicklistNode *prev; // 指向上一个ziplist节点
  11. struct quicklistNode *next; // 指向下一个ziplist节点
  12. unsigned char *zl; // 数据指针,如果没有被压缩,就指向ziplist结构,反之指向 quicklistLZF结构
  13. unsigned int sz; // 表示指向ziplist结构的总长度(内存占用长度)
  14. unsigned int count : 16; // 表示ziplist中的数据项个数
  15. unsigned int encoding : 2; // 编码方式,1--ziplist,2--quicklistLZF
  16. unsigned int container : 2; // 预留字段,存放数据的方式,1--NONE,2--ziplist
  17. unsigned int recompress : 1; // 解压标记,当查看一个被压缩的数据时,需要暂时解压,标记此参数为 1,之后再重新进行压缩
  18. unsigned int attempted_compress : 1; // 测试相关
  19. unsigned int extra : 10; // 扩展字段,暂时没用
  20. } quicklistNode;
复制代码

数据压缩
  quicklist每个节点的现实 数据存储布局 为ziplist,这种布局 的上风 在于节流 存储空间。为了进一步降低ziplist的存储空间,还可以对ziplist举行 压缩。Redis采用的压缩算法是LZF。其基本头脑 是:数据与前面重复的记录重复位置及长度,不重复的记录原始数据。

  压缩过后的数据可以分成多个片断 ,每个片断 有两个部分:表明 字段和数据字段。quicklistLZF的布局 体如下:

  1. /* quicklistLZF is a 4+N byte struct holding 'sz' followed by 'compressed'.
  2. * 'sz' is byte length of 'compressed' field.
  3. * 'compressed' is LZF data with total (compressed) length 'sz'
  4. * NOTE: uncompressed length is stored in quicklistNode->sz.
  5. * When quicklistNode->zl is compressed, node->zl points to a quicklistLZF */
  6. typedef struct quicklistLZF {
  7. unsigned int sz; /* LZF压缩后占用的字节数*/
  8. char compressed[]; //柔性数组,指向数据部分
  9. } quicklistLZF;
复制代码

应用场景
列表(List)的底层实现、发布与订阅、慢查询、监视器等功能。

流对象

stream告急 由:消息、生产者、斲丧 者和斲丧 组构成。

在这里插入图片形貌

Redis Stream的底层告急 利用 了listpack(紧凑列表)和Rax树(基数树)。

listpack
listpack表示一个字符串列表的序列化,listpack可用于存储字符串或整数。用于存储stream的消息内容。
布局 如下图:

在这里插入图片形貌

Rax树
Rax 是一个有序字典树 (基数树 Radix Tree),按照 key 的字典序分列 ,支持快速地定位、插入和删除操作。

在这里插入图片形貌

  

Rax 被用在 Redis Stream 布局 内里 用于存储消息队列,在 Stream 内里 消息 ID 的前缀是时间戳 + 序号,如许 的消息可以明白 为时间序列消息。利用 Rax 布局 举行 存储就可以快速地根据消息 ID 定位到具体 的消息,然后继续遍历指定消息 之后的全部 消息。

在这里插入图片形貌

应用场景:
stream的底层实现

10种encoding

  1. /* Objects encoding. Some kind of objects like Strings and Hashes can be
  2. * internally represented in multiple ways. The 'encoding' field of the object
  3. * is set to one of this fields for this object. */
  4. #define OBJ_ENCODING_RAW 0 /* Raw representation */
  5. #define OBJ_ENCODING_INT 1 /* Encoded as integer */
  6. #define OBJ_ENCODING_HT 2 /* Encoded as hash table */
  7. #define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
  8. #define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
  9. #define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
  10. #define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
  11. #define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
  12. #define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
  13. #define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
  14. #define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
复制代码

encoding 表示对象的内部编码,占 4 位。

Redis通过 encoding 属性为对象设置不同的编码

对于少的和小的数据,Redis采用小的和压缩的存储方式,表现 Redis的机动 性

大大进步 了 Redis 的存储量和实行 服从

比如Set对象:

intset : 元素是64位以内的整数

hashtable:元素是64位以外的整数

  1. 127.0.0.1:6379> sadd set:001 1 3 5 6 2
  2. (integer) 5
  3. 127.0.0.1:6379> object encoding set:001
  4. "intset"127.0.0.1:6379> sadd set:004 1 100000000000000000000000000 9999999999
  5. (integer) 3
  6. 127.0.0.1:6379> object encoding set:004
  7. "hashtable"
复制代码

String

int、raw、embstr

int

REDIS_ENCODING_INT(int范例 的整数)

  1. 127.0.0.1:6379> set n1 123
  2. OK
  3. 127.0.0.1:6379> object encoding n1
  4. "int"
复制代码

embstr

REDIS_ENCODING_EMBSTR(编码的简单动态字符串)
小字符串 长度小于44个字节

  1. 127.0.0.1:6379> set name:001 zhangfei
  2. OK
  3. 127.0.0.1:6379> object encoding name:001
  4. "embstr"
复制代码

raw

REDIS_ENCODING_RAW (简单动态字符串)
大字符串 长度大于44个字节

  1. 127.0.0.1:6379> set address:001 asdasdasdasdasdasdsadasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdas
  2. OK
  3. 127.0.0.1:6379> object encoding address:001
  4. "raw"
复制代码

list

列表的编码是quicklist。
REDIS_ENCODING_QUICKLIST(快速列表)

  1. 127.0.0.1:6379> lpush list:001 1 2 5 4 3
  2. (integer) 5
  3. 127.0.0.1:6379> object encoding list:001
  4. "quicklist"
复制代码

hash

散列的编码是字典和压缩列表

dict

REDIS_ENCODING_HT(字典)
当散列表元素的个数比较多或元素不是小整数或短字符串时。

  1. 127.0.0.1:6379> hmset user:003 username111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111 zhangfei password 111 num 2300000000000000000000000000000000000000000000000000
  2. OK
  3. 127.0.0.1:6379> object encoding user:003
  4. "hashtable"
复制代码

ziplist

REDIS_ENCODING_ZIPLIST(压缩列表)
当散列表元素的个数比较少,且元素都是小整数或短字符串时。

  1. 127.0.0.1:6379> HSET user:001 username zhanyun password 123456
  2. (integer) 2
  3. 127.0.0.1:6379> OBJECT encoding user:001
  4. "ziplist"
复制代码

set

集合的编码是整形集合和字典

intset

REDIS_ENCODING_INTSET(整数集合)
当Redis集合范例 的元素都是整数并且都处在64位有符号整数范围内(-9223372036854775808 ~ 9223372036854775807)

  1. 127.0.0.1:6379> sadd set:001 1 3 5 6 2
  2. (integer) 5
  3. 127.0.0.1:6379> object encoding set:001
  4. "intset"
复制代码

dict

REDIS_ENCODING_HT(字典)
当Redis集合范例 的元素黑白 整数或都处在64位有符号整数范围外(>9223372036854775807)

  1. 127.0.0.1:6379> sadd set:004 1 100000000000000000000000000 9999999999
  2. (integer) 3
  3. 127.0.0.1:6379> object encoding set:004
  4. "hashtable"
复制代码

zset

有序集合的编码是压缩列表和跳跃表+字典

ziplist

REDIS_ENCODING_ZIPLIST(压缩列表)

当元素的个数比较少,且元素都是小整数或短字符串时。

  1. 127.0.0.1:6379> zadd hit:1 100 item1 20 item2 45 item3
  2. (integer) 3
  3. 127.0.0.1:6379> object encoding hit:1
  4. "ziplist"
复制代码

skiplist + dict

REDIS_ENCODING_SKIPLIST(跳跃表+字典)

当元素的个数比较多或元素不是小整数或短字符串时。

  1. 127.0.0.1:6379> zadd hit:2 100 item1111111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111 20 item2 45 item3
  2. (integer) 3
  3. 127.0.0.1:6379> object encoding hit:2
  4. "skiplist"
复制代码

到此这篇关于Redis底层数据布局 的文章就先容 到这了,更多相干 Redis数据布局 内容请搜刮 脚本之家从前 的文章或继续欣赏 下面的相干 文章渴望 大家以后多多支持脚本之家!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

avatar vvvvvvyb | 2021-9-18 08:37:54 | 显示全部楼层
祖国尚未统一,我却天天灌水,好内疚!
回复

使用道具 举报

avatar 我是的十八簿 | 2021-9-20 10:01:15 | 显示全部楼层
admin楼主是男的还是女的?
回复

使用道具 举报

avatar 咑啲呿迗嘡迗qc | 2021-9-21 08:21:18 | 显示全部楼层
admin楼主的头像能辟邪啊!
回复

使用道具 举报

avatar 啵啵小奥特 | 2021-9-26 18:26:52 | 显示全部楼层
帖子很有深度!
回复

使用道具 举报

avatar jj13904198394 | 2021-10-16 01:14:18 | 显示全部楼层
回帖也有有水平的!
回复

使用道具 举报

admin楼主练了葵花宝典吧?
回复

使用道具 举报

听admin楼主一席话,省我十本书!
回复

使用道具 举报

avatar 莫言941 | 前天 13:05 | 显示全部楼层
最近压力山大啊!
回复

使用道具 举报

avatar 123457176 | 昨天 01:53 | 显示全部楼层
勤奋灌水,天天向上!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则