Redis底层原理

比特霜焰引
• 阅读 3675

对比另一个著名的缓存中间件memcached,redis提供了更加丰富的数据结构和命令,它支持基于列表、集合、哈希表等多种数据结构。这些结构在redis中是由6种底层数据结构来实现:

  • 简单动态字符串
  • (SDS)
  • 链表
  • 字典
  • 跳跃表
  • 整数
  • 集合
  • 压缩列表

Redis底层原理

SDS

用来保存redis数据库中的字符串,它是一个结构体:

Redis底层原理

结构体中的三个属性分别用来表示已使用的字节数量、未使用的字节数量、字节数组,redis之所以设计这个结构而不使用C语言中的字符串,是因为SDS结构相比C语言中的字符串有如下优点:

  • 记录了字符串的长度,执行strlen操作时,复杂度为O(1),而普通字符串为O(n)。
  • SDS采用预先分配和惰性释放的优化策略,减少重新分配空间的次数,其中有free字段记录未使用空间字节数。
  • 二进制安全,除了可以存储字符还可以存储任意二进制。
  • SDS操作函数会自动检查空间是否足够并且空间不足时自动扩展空间,从而防止内存溢出。

链表

用来存储链表结构数据,它被用来实现SADD等集合命令:

Redis底层原理

字典

字典在Redis中应用非常广泛,Redis数据库本身就是使用字典来作为底层实现的,比如我们执行命令:SET msg "hello world",redis就会在数据库中创建一个键为msg值为"hello world"的字典。

字典在实现上包含两个hash表,常规状态下,只有第一个hash表存储数据,当发生rehash时,会给第二个hash表分配空间,并且把第一个hash表中的数据拷贝到第二个hash表中。如果hash表中的数据量比较大时,会采用渐进式rehash,分多次完成,字典中有个rehashindex字段记录rehash进度(如果当前未进行rehash值为-1),这样的话在字典中查询数据时,可能会查找两个hash表,先查第一个表,如果查不到再查第二个,但是新增的数据都会添加到第二个hash表中,发生rehash之后会由第二hash表负责查询客户端请求数据。当服务器正在执行BGSAVE、BGREWRITEAOF等耗CPU的命令时,会尽量避免rehash操作。

Redis底层原理

跳跃表

redis实现了一个跳跃表结构,跳跃表被用来实现缓存中的有序集合如ZADD等命令。

Redis底层原理

Redis底层原理

整数集合

当集合中只包含整数时,并且集合中的元素数量不多时,redis会采用整数集合当作底层实现。

Redis底层原理

其中contents中的元素有可能是16、32、64字节,redis只会分配合适的内存,比如当前添加的时16位的整数,那么只会给contents元素分配16字节,后续往数组中再次添加16字节以上的整数时,会给该数组升级重新分配32或64字节内存,数组只能升级不能降级,能从16字节升级到32或64字节,但是不能从64字节降级到16或32字节。

压缩列表

当列表、集合、hash表、有序集合等结构中的元素数量小于某个阀值,redis会采用压缩列表当作这些结构的底层实现,目的是为了节省内存,压缩列表包含了下列各个组成部分:

  • zlbytes 4字节,纪录整个压缩列表占用的内存字节数:在对压缩列表进行内存重分配,或计算zlend时使用。
  • zltail 4字节,纪录压缩列表表尾节点距离压缩列表的起始地址有多少个字节,通过这个偏移量程序可以无须遍历整个压缩列表就可以确定表尾节点的地址。
  • zllen 2字节,纪录压缩列表包含的节点数量,当属性值等于UINT16_MAX时,结点的真实数量需要遍历整个压缩列表才能计算得出。
  • entryX,列表节点,长度由结点中的内存结点,结点中有个字段previous_entry_length记录了前一个几点的长度,当结点的长度在254左右时,对某结点的修改可能会引发所有结点的连锁更新。

Redis底层原理

压缩列表会节约内存,但是访问或修改结构中的元素时会损失一些性能,所以当元素数量或者元素大小超过了某个阀值之后会对值对象进行编码转换,转换成集合、hash表、有序集合等结构,并重新分配内存。

对象

Redis并没有直接使用上面那些数据结构来实现键值对数据库,而是在这些数据接口的基础上创建了一个对象系统,每次在Redis数据库中新创建一个键值对时,至少会创建两个对象,一个键对象,一个值对象。每个对象都包含指定的类型和编码。

对象类型

对象的type属性设置,可以通过TYPE命令来输出对象的类型,对象有下面几种类型:

  • 字符串对象:类型常量为REDIS_STRING,输出值string。
  • 列表对象:类型常量为REDIS_LIST,输出值list。
  • 哈希对象:类型常量为REDIS_HASH,输出值hash。
  • 集合对象:类型常量为REDIS_SET,输出值hash。
  • 有序集合表对象:类型常量为REDIS_ZSET,输出值zset。

对象编码

对象的encoding属性设置,可以通过OBJECT ENCODING命令查看对象的编码,对象有下面几种编码:

  • long类型整数,REDIS_ENCODING_INT,输出intembstr编码的SDS,REDIS_ENCODING_EMBSTR,输出embstr。
  • embstr编码是专门用于保存短字符串的一种优化编码方式,跟正常的字符编码相比,字符编码会调用两次内存分配函数来分别创建redisObject和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间,空间中一次包含redisObject和sdshdr两个结构
  • SDS,REDIS_ENCODING_RAW,输出raw
  • 字典,REDIS_ENCODING_HT,输出hashtable
  • 双端链表,REDIS_ENCODING_LINKEDLIST,输出linkedlist
  • 压缩列表,REDIS_ENCODING_ZIPLIST,输出ziplist
  • 整数集合REDIS_ENCODING_INISET,输出intset
  • 跳跃表和字典,REDIS_ENCODING_SKIPLIST,输出skiplist

每种类型的对象至少使用了两种不同的编码,在不同的条件下redis会对对象进行编码转换,比如如果对象保存的全部都是整数,那么他的编码是int,但是当执行了一些命令之后对象中存储的已经不全部是整数了,那么会把该对象的编码从int变为raw,其它类型的对象同理。

点赞
收藏
评论区
推荐文章
redis数据结构底层实现
一.redis常用的数据结构有哪几种?1.简单字符串:String2.列表:List3.键值对:Hash4.唯一集合:Set5.有序唯一集合:SortedSet二.每种数据结构对应的底层实现1.首先需要知道
深入理解跳表及其在Redis中的应用
跳表可以达到和红黑树一样的时间复杂度O(logN),且实现简单,Redis中的有序集合对象的底层数据结构就使用了跳表。其作者威廉·普评价:跳跃链表是在很多应用中有可能替代平衡树的一种数据结构。本篇文章将对跳表的实现及在Redis中的应用进行学习。
Stella981 Stella981
3年前
Django 之redis的应用
redis概述redis是一种nosql数据库,他的数据是保存在内存中,同时redis可以定时把内存数据同步到磁盘,即可以将数据持久化,并且他比memcached支持更多的数据结构(string,list列表队列和栈,set集合,sortedset有序集合,hash(hash表))
Stella981 Stella981
3年前
Redis 为什么这么快? Redis 的有序集合 zset 的底层实现原理是什么? —— 跳跃表 skiplist
Redis有序集合zset的底层实现——跳跃表skiplistRedis简介Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。它支持多种类型的数据结构,如字符串(Strings),散列(Hash),列表(List),集合(S
Stella981 Stella981
3年前
Redis基础与性能调优
Redis是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库、缓存服务或消息服务使用。Redis支持多种数据结构,包括字符串、哈希表、链表、集合、有序集合、位图、Hyperloglogs等。Redis具备LRU淘汰、事务实现、以及不同级别的硬盘持久化等能力,并且支持副本集和通过RedisSentinel实现的高可用方案,
Stella981 Stella981
3年前
Redis是什么
redis是Nosql数据库,是一个keyvalue存储系统。可用于缓存,事件发布或订阅,高速队列等场景。该数据库使用ANSIC语言编写,支持网络,提供字符串,哈希,列表,队列,集合结构直接存取,基于内存,可持久化。虽然redis是keyvalue的存储系统,但是redis支持的value存储类型是非常的多,比如字符串、链表、集合、有序集合和哈希。
Stella981 Stella981
3年前
Redis为什么这么快
Redis简介Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件它支持多种类型的数据结构,如字符串(String),散列(Hash),列表(List),集合(Set),有序集合(SortedSet或者是ZSet)与范围查询,Bitmaps,Hyperloglogs和
Stella981 Stella981
3年前
Redis内存淘汰机制
摘要Redis是一款优秀的、开源的内存数据库,我在阅读Redis源码实现的过程中,时时刻刻能感受到Redis作者为更好地使用内存而费尽各种心思,例如最明显的是对于同一种数据结构在不同应用场景下提供了基于不同底层编码的实现(如压缩列表、跳跃表等)。今天我们暂时放下对Redis不同数据结构的探讨,来一起看看Redis提供的另一种机制——内存淘汰机制。
Stella981 Stella981
3年前
Redis实现之对象(一)
对象前面我们介绍了Redis的主要数据结构,如:简单动态字符串SDS、双端链表、字典、压缩列表、整数集合等。Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,每种对象都用到了至少一种我们之前介绍的数据结构通过这五种
Stella981 Stella981
3年前
Redis 底层数据结构介绍
!Redis底层数据结构(https://oscimg.oschina.net/oscnet/2bdc88a69f3d195776f6b395ddc914775f8.png)Redis底层数据结构版本:2.9支持的数据类型:1.字符串2.散列3.列表4.集合5.有序集合字符串
Stella981 Stella981
3年前
Redis 避不开的五种数据结构
Redis中有5种数据结构,分别是字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(SortedSet),因为使用Redis场景的开发中肯定是无法避开这些基础结构的,所以熟练掌握它们也就成了一项必不可少的能力。本文章精要地介绍了Redis的这几种数据结构,主要覆盖了它们各自的定义、基本用法与相关要点。字