Redis专题(2):Redis数据结构底层探秘

作者:网友投稿 时间:2019-06-13 01:47

字号

上篇文章Redis闲谈(1):构建知识图谱介绍了Redis的基本概念、优缺点以及它的内存淘汰机制,相信大家对Redis有了初步的认识。互联网的很多应用场景都有着Redis的身影,它能做的事情远远超出了我们的想像。Redis的底层数据结构到底是什么样的呢,为什么它能做这么多的事情?本文将探秘Redis的底层数据结构以及常用的命令。

本文知识脑图如下:

Redis专题(2):Redis数据结构底层探秘

一、Redis的数据模型

用 键值对 name:"小明"来展示Redis的数据模型如下:

Redis的数据模型

dictEntry:在一些编程语言中,键值对的数据结构被称为字典,而在Redis中,会给每一个key-value键值对分配一个字典实体,就是“dicEntry”。dicEntry包含三部分: key的指针、val的指针、next指针,next指针指向下一个dicteEntry形成链表,这个next指针可以将多个哈希值相同的键值对链接在一起,通过链地址法来解决哈希冲突的问题

sds :Simple Dynamic String,简单动态字符串,存储字符串数据。

redisObject:Redis的5种常用类型都是以RedisObject来存储的,redisObject中的type字段指明了值的数据类型(也就是5种基本类型)。ptr字段指向对象所在的地址。

RedisObject对象很重要,Redis对象的类型、内部编码、内存回收、共享对象等功能,都是基于RedisObject对象来实现的。

这样设计的好处是:可以针对不同的使用场景,对5种常用类型设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率。

Redis将jemalloc作为默认内存分配器,减小内存碎片。jemalloc在64位系统中,将内存空间划分为小、大、巨大三个范围;每个范围内又划分了许多小的内存块单位;当Redis存储数据时,会选择大小最合适的内存块进行存储。

二、Redis支持的数据结构

Redis支持的数据结构有哪些?

如果回答是String、List、Hash、Set、Zset就不对了,这5种是Redis的常用基本数据类型,每一种数据类型内部还包含着多种数据结构。

用encoding指令来看一个值的数据结构。比如:

127.0.0.1:6379> set name tom 

OK 

127.0.0.1:6379> object encoding name 

"embstr 

此处设置了name值是tom,它的数据结构是embstr,下文介绍字符串时会详解说明。

127.0.0.1:6379> set age 18 

OK 

127.0.0.1:6379> object encoding age 

"int" 

如下表格总结Redis中所有的数据结构类型:

Redis专题(2):Redis数据结构底层探秘

补充说明:

假如面试官问:Redis的数据类型有哪些?

回答:String、list、hash、set、zet

 

一般情况下这样回答是正确的,前文也提到Redis的数据类型确实是包含这5种,但细心的同学肯定发现了之前说的是“常用”的5种数据类型。其实,随着Redis的不断更新和完善,Redis的数据类型早已不止5种了。

登录Redis的官方网站打开官方的数据类型介绍(https://redis.io/topics/data-types-intro):

Redis专题(2):Redis数据结构底层探秘

发现Redis支持的数据结构不止5种,而是8种,后三种类型分别是:

位数组(或简称位图):使用特殊命令可以处理字符串值,如位数组:您可以设置和清除各个位,将所有位设置为1,查找第一个位或未设置位,等等。

HyperLogLogs:这是一个概率数据结构,用于估计集合的基数。不要害怕,它比看起来更简单。

Streams:仅附加的类似于地图的条目集合,提供抽象日志数据类型。

本文主要介绍5种常用的数据类型,上述三种以后再共同探索。

1. string字符串

字符串类型是Redis最常用的数据类型,在Redis中,字符串是可以修改的,在底层它是以字节数组的形式存在的。

Redis中的字符串被称为简单动态字符串「SDS」,这种结构很像Java中的ArrayList,其长度是动态可变的。

struct SDS<T> { 

  T capacity; // 数组容量 

  T len; // 数组长度 

  byte[] content; // 数组内容 

Redis专题(2):Redis数据结构底层探秘

content[] 存储的是字符串的内容,capacity表示数组分配的长度,len表示字符串的实际长度。

字符串的编码类型有int、embstr和raw三种,如上表所示,那么这三种编码类型有什么不同呢?

int 编码:保存的是可以用 long 类型表示的整数值。

raw 编码:保存长度大于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

embstr 编码:保存长度小于44字节的字符串(redis3.2版本之前是39字节,之后是44字节)。

设置一个值测试一下:

127.0.0.1:6379> set num 300 

127.0.0.1:6379> object encoding num 

"int" 

127.0.0.1:6379> set key1 wealwaysbyhappyhahaha 

OK 

127.0.0.1:6379> object encoding key1 

"embstr" 

127.0.0.1:6379> set key2 hahahahahahahaahahahahahahahahahahahaha 

OK 

127.0.0.1:6379> strlen key2 

(integer) 39 

127.0.0.1:6379> object encoding key2 

"embstr" 

127.0.0.1:6379> set key2 hahahahahahahaahahahahahahahahahahahahahahaha 

OK 

127.0.0.1:6379> object encoding key2 

"raw" 

127.0.0.1:6379> strlen key2 

(integer) 45 

aw类型和embstr类型对比:

embstr编码的结构:

Redis专题(2):Redis数据结构底层探秘

raw编码的结构:

Redis专题(2):Redis数据结构底层探秘

责任编辑:CQITer新闻报料:400-888-8888   本站原创,未经授权不得转载
关键词 >>Redis 软件 开发
继续阅读
热新闻
推荐
关于我们联系我们免责声明隐私政策 友情链接