Redis(设计与实现)
文章平均质量分 84
本专栏从Redis的源码实现角度来讲解Redis,内容包含但不限于Redis的数据结构、工作原理...,有问题文章下留言。最后感谢黄健宏先生的著作《Redis设计与实现》
董哥的黑板报
90后程序员!
展开
-
Redis(设计与实现):01---数据结构之SDS动态字符串(raw、embstr、int、struct sdshdr)
一、动态字符串(SDS)介绍Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组,以下简称C字 符串),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS用作Redis的默认字符串表示 在Redis里面,C字符串只会作为字符串字面量(string literal)用在一些无须对字符串值 进行修改的地方,比如打印日志...原创 2019-11-23 22:42:08 · 1195 阅读 · 3 评论 -
Redis(设计与实现):02---数据结构之链表(linkedlist、struct listNode、struct list)
一、Redis使用链表链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点 来灵活地调整链表的长度 作为一种常用数据结构,链表内置在很多高级的编程语言里面,因为Redis使用的C语言 并没有内置这种数据结构,所以Redis构建了自己的链表实现二、链表在Redis中的应用场景 ①链表在Redis中的应用非常广泛,比如列表键的底层实现之一就是链表。当一个列表键包 ...原创 2019-11-23 22:55:17 · 766 阅读 · 0 评论 -
Redis(设计与实现):03---数据结构之字典(hashtable、struct dictht、struct dictEntry、struct dict)
一、字典介绍字典,又称为符号表(symbol table)、关联数组(associative array)或映射(map), 是一种用于保存键值对(key-value pair)的抽象数据结构 在字典中,一个键(key)可以和一个值(value)进行关联(或者说将键映射为值), 这些关联的键和值就称为键值对 字典中的每个键都是独一无二的,程序可以在字典中根据键查找与之关联的值,或者通过键来...原创 2019-11-24 11:14:54 · 736 阅读 · 0 评论 -
Redis(设计与实现):04---数据结构之整数集合(intset、struct intset)
一、整数集合在Redis中的应用整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现 举个例子,如果我们创建一个只包含五个元素的集合键,并且集合中的所有元素都是整 数值,那么这个集合键的底层实现就会是整数集合:redis> SADD numbers 1 3 5 7 9(intege...原创 2019-11-24 13:55:35 · 402 阅读 · 0 评论 -
Redis(设计与实现):05---数据结构之跳跃表(skiplist、struct zskiplistNode、struct zskiplist)
一、跳跃表介绍跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的 指针,从而达到快速访问节点的目的 跳跃表支持平均O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来 批量处理节点 在大部分情况下,跳跃表的效率可以和平衡树相媲美,并且因为跳跃表的实现比平衡树 要来得更为简单,所以有不少程序都使用跳跃表来代替平衡树二、跳跃表在Redis中...原创 2019-11-24 13:56:10 · 433 阅读 · 0 评论 -
Redis(设计与实现):06---数据结构之压缩列表(ziplist、struct ziplist)
一、压缩列表在Redis中的应用压缩列表(ziplist)是列表键和哈希键的底层实现之一 当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用 压缩列表来做列表键的底层实现 例如,执行以下命令将创建一个压缩列表实现的列表键(列表键里面包含的都是1、3、5、10086这样的小整数值,以及"hello"、"world"这样的短 字符串...原创 2019-11-24 14:32:59 · 383 阅读 · 0 评论 -
Redis(设计与实现):07---对象之类型与编码(struct redisObject)
一、对象介绍在前面的文章里,我们陆续介绍了Redis用到的所有主要数据结构,比如简单动态字 符串(SDS)、双端链表、字典、压缩列表、整数集合等等 Redis并没有直接使用这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,每种对象都用到了至少一种我们前面所介绍的数据结构 优点: 通过...原创 2019-11-24 15:42:35 · 428 阅读 · 0 评论 -
Redis(设计与实现):08---对象之字符串对象(string)
一、字符串的编码字符串对象的编码可以是int、raw或者embstr①int型编码如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字 符串对象会将整数值保存在字符串对象结构的ptr属性里面(将void*转换成long),并将字符串对象的编码设置为int 举个例子,如果我们执行以下SET命令,那么服务器将创建一个int编码的字符串对象作为number键...原创 2019-11-25 11:10:51 · 391 阅读 · 0 评论 -
Redis(设计与实现):09---对象之列表对象(list)
一、列表对象的编码列表对象的编码可以是ziplist或者linkedlistziplist型编码ziplist编码的列表对象使用压缩列表作为底层实现,每个压缩列表节点(entry)保存了一个列表元素 举个例子,如果我们执行以下RPUSH命令,那么服务器将创建一个列表对象作为numbers键的值,如果numbers键的值对象使用的是ziplist编码,这个值对象将会是下图所展示的样子:...原创 2019-11-25 11:24:29 · 659 阅读 · 0 评论 -
Redis(设计与实现):10---对象之哈希对象(hash)
一、哈希对象的编码哈希对象的编码可以是ziplist或者hashtableziplist型编码ziplist编码的哈希对象使用压缩列表作为底层实现 每当有新的键值对要加入到哈希对象 时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入到压缩列表表尾,因此: 保存了同一键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在 后 先添...原创 2019-11-25 12:58:17 · 618 阅读 · 0 评论 -
Redis(设计与实现):11---对象之集合对象(set)
一、集合对象的编码集合对象的编码可以是intset或者hashtableintset型编码ntset编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在 整数集合里面 举个例子,以下代码将创建一个如下图所示的intset编码集合对象:hashtable型编码hashtable编码的集合对象使用字典作为底层实现 字典的每个键都是一个字符串对象,每...原创 2019-11-25 13:05:17 · 437 阅读 · 0 评论 -
Redis(设计与实现):12---对象之有序集合对象(zset)
待续原创 2019-11-25 13:06:26 · 408 阅读 · 0 评论 -
Redis(设计与实现):13---对象之类型检查与命令多态
Redis中用于操作键的命令基本上可以分为两种类型:①其中一种命令可以对任何类型的键执行,比如说DEL命令、EXPIRE命令、RENAME命 令、TYPE命令、OBJECT命令等 ②而另一种命令只能对特定类型的键执行,比如说: SET、GET、APPEND、STRLEN等命令只能对字符串键执行; HDEL、HSET、HGET、HLEN等命令只能对哈希键执行 RPUSH、LPOP、L...原创 2019-11-25 13:19:37 · 341 阅读 · 0 评论 -
Redis(设计与实现):14---对象之内存回收与对象共享(refcount属性、REDIS_SHARED_INTEGERS常量)
一、内存回收概念:因为C语言并不具备自动内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收refcount属性每个对象的引用计数信息由redisObject结构的refcount属性记录:typedef struct ...原创 2019-11-25 13:33:57 · 646 阅读 · 0 评论 -
Redis(设计与实现):15---对象之空转时长(OBJECT IDLETIME命令、lru属性、maxmemory选项)
一、概念(lru属性)redisObject结构包含的最后一个属性为lru属性,该属性记录了对象最后一次被命令程序访问的时间typedef struct redisObject { // ... unsigned lru:22; // ...} robj;二、空转时长(OBJECT IDLETIME命令)OBJECT IDLETIME命令可以打印出给定键的...原创 2019-11-25 13:40:37 · 675 阅读 · 0 评论 -
Redis(设计与实现):16---数据库之服务器中的数据库(struct redisDb、dbnum属性、database选项、db属性、SELECT命令)
一、服务器中的数据库Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组的每个项都是一个redis.h/redisDb结构,每个redisDb结构代表一个数据库:struct redisServer { // ... redisDb *db; // 一个数组,保存着服务器中的所有数据库 // ...};...原创 2019-11-25 20:47:42 · 510 阅读 · 0 评论 -
Redis(设计与实现):17---数据库之键值对的添加、删除、更新、取值、维护(struct dict)
数据库键空间Redis是一个键值对(key-value pair)数据库服务器,服务器中的每个数据库都由一redis.h/redisDb结构表示,其中,redisDb结构的dict字典保存了数据库中的所有键值对,我们将这个字典称为键空间(key space):typedef struct redisDb { // ... dict *dict;//数据库键空间,保存着数据...原创 2019-11-25 21:10:09 · 1568 阅读 · 0 评论 -
Redis(设计与实现):18---数据库之键的生存时间、过期时间(EXPIRE、PEXPIRE、EXPIREAT、PEXPIREAT、PERSIST、TTL、PTTL)
键的生存时间或过期时间介绍生存时间(Time To Live,TTL):在经过指定的秒数或者毫秒数之后,服务器就会自动删除生存时间为0的键 过期时间(expire time):是一个UNIX时间戳,当键的过期时间来临时,服务器就会自动从数据库中删除这个键一、设置键生存/过期时间(EXPIRE、PEXPIRE、EXPIREAT、PEXPIREAT)设置生存时间: EXPIRE <...原创 2019-11-25 23:01:02 · 1642 阅读 · 0 评论 -
Redis(设计与实现):19---数据库之键的过期删除策略(expireIfNeeded、activeExpireCycle)
如果一个键过期了,可以有下面3个过期删除策略:①定时删除(Redis不支持) ②惰性删除 ③定期删除注意:在这3种策略中,第①种和第③种为主动删除策略,而第②种则为被动删除策略 Redis服务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,服务器可以 很好地在合理使用CPU时间和避免浪费内存空间之间取得平衡一、定时删除概念:在设置键的过期时间的同时,创建...原创 2019-11-28 11:26:59 · 1014 阅读 · 0 评论 -
Redis(设计与实现):20---数据库之AOF、RDB、复制功能对过期键的处理
一、RDB与过期键的关系生成RDB文件在执行SAVE命令或者BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键进 行检查,已过期的键不会被保存到新创建的RDB文件中 因此,数据库中包含过期键不会对生成新的RDB文件造成影响 举个例子,如果数据库中包含三个键k1、k2、k3,并且k2已经过期,那么当执行SAVE命 令或者BGSAVE命令时,程序只会将k1和k3的数据保存到R...原创 2019-11-28 11:43:01 · 452 阅读 · 0 评论 -
Redis(设计与实现):21---数据库之数据库通知(SUBSCRIBE命令、notify-keyspace-events选项、notifyKeyspaceEvent函数)
一、数据库通知介绍数据库通知是Redis 2.8版本新增加的功能,这个功能可以让客户端通过订阅给定的频道或者模式,来获知数据库中键的变化,以及数据库中命令的执行情况 分类: 键空间通知:“某个键执行了什么命令”的通知称为键空间通知(key-space notification) 键事件通知:键事件通知(key-event notification)关注的是“某个命令被什么键执行了” ...原创 2019-11-28 12:24:39 · 6076 阅读 · 5 评论 -
Redis(设计与实现):22---RDB持久化之RDB文件的创建与载入(SAVE命令、BGSAVE命令、rdbSave函数、rdbLoad函数)
数据库状态Redis是一个键值对数据库服务器,服务器中通常包含着任意个非空数据库,而每个非空数据库中又可以包含任意个键值对,为了方便起见,我们将服务器中的非空数据库以及它们的键值对统称为数据库状态一、RDB持久化介绍因为Redis是内存数据库,它将自己的数据库状态储存在内存里面,所以如果不想办法将储存在内存中的数据库状态保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据库状态也会消失...原创 2019-11-28 12:53:56 · 923 阅读 · 0 评论 -
Redis(设计与实现):23---RDB持久化之自动间隔性保存(save选项、struct saveparam、dirty属性、lastsave属性)
一、自动间隔性保存介绍(save选项)前面一篇文章介绍了SAVE、BGSAVE命令,其中BGSAVE命令可以在不阻塞服务器进程的情况下执行,所以Redis允许用户通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令save选项的格式用户可以通过save选项设置多个保存条件,但只要其中任意一个条件被满足,服务器就会执行BGSAVE命令 如果用户没有主动设置...原创 2019-11-28 16:58:05 · 930 阅读 · 0 评论 -
Redis(设计与实现):24---RDB持久化之RDB文件结构
总体结构RDB文件为二进制格式保存,下面我们为了演示效果,采用字符串的形式演示REDIS(常量):RDB文件的最开头是REDIS部分,这个部分的长度为5字节,保存着“REDIS”五个字符。 通过这五个字符,程序可以在载入文件时,快速检查所载入的文件是否RDB文件 db_version(变量):长度为4字节,它的值是一个字符串表示的整数,这个整数记录了RDB文件的 版本号,比如"00...原创 2019-11-28 17:51:06 · 487 阅读 · 0 评论 -
Redis(设计与实现):25---RDB持久化之od命令解析RDB文件
待续原创 2020-12-21 16:04:46 · 817 阅读 · 0 评论 -
Redis(设计与实现):26---AOF持久化之AOF文件的写入与还原(aof_buf缓冲区、flushAppendOnlyFile函数、appendfsync选项)
AOF持久化介绍除了RDB持久化功能之外,Redis还提供了AOF(Append Only File)持久化功能。与 RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的,如下图所示:AOF文件介绍开启AOF持久化功能之后,Redis会将你本次在数据库中所操作的写记录追加到一个文件中(系统会自动在第一行...原创 2019-11-28 21:43:42 · 935 阅读 · 1 评论 -
Redis(设计与实现):27---AOF持久化之AOF文件重写(aof_rewrite函数、REDIS_AOF_REWRITE_ITEMS_PER_CMD常量、BGREWRITEAOF命令)
一、AOF文件重写的概念为什么需要AOF文件重写举个例子,如果客户端执行了以下命令:那么服务器为了保存当前list键的状态,必须在AOF文件中写入六条命令 因为AOF持久化是通过保存被执行的写命令来记录数据库状态的,所以随着服务器运行时间的流逝,AOF文件中的内容会越来越多,文件的体积也会越来越大,如果不加以控制的话,体积过大的AOF文件很可能对Redis服务器、甚至整个宿主计算...原创 2019-11-28 22:05:54 · 770 阅读 · 0 评论 -
Redis(设计与实现):28---事件之文件事件(AE_READABLE事件、AE_WRITABLE事件)
一、文件事件介绍文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进 行连接,而文件事件就是服务器对套接字操作的抽象。服务器与客户端(或者其他服务器) 的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信 操作二、文件事件处理器Redis基于Reactor模式开发了自己的网络事件处理器,这个处理器被称为文件事件处理...原创 2019-11-28 22:29:04 · 1561 阅读 · 0 评论 -
Redis(设计与实现):29---事件之时间事件(serverCron函数、hz选项)
一、时间事件介绍时间事件(time event):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象二、时间事件的分类Redis的时间事件分为以下两类: 定时事件:让一段程序在指定的时间之后执行一次。比如说,让程序X在当前时间的30 毫秒之后执行一次 周期性事件:让一段程序每隔指定时间就执行一次。比如说,让...原创 2019-11-28 22:52:06 · 797 阅读 · 0 评论 -
Redis(设计与实现):30---事件之服务器的事件调度与执行(aeProcessEvents函数)
一、服务器事件的调度与执行因为服务器中同时存在文件事件和时间事件两种事件类型,所以服务器必须对这两种事件进行调度,决定何时应该处理文件事件,何时又应该处理时间事件,以及花多少时间来处 理它们等等二、aeProcessEvents函数事件的调度和执行由ae.c/aeProcessEvents函数负责 以下是该函数的伪代码表示: 备注:在实际中,处理已产生文件事件的代码是直接写在aePr...原创 2019-11-29 21:26:19 · 838 阅读 · 0 评论 -
Redis(设计与实现):31---客户端之客户端属性(clients属性、redisClient、fd、name、flags、querybuf、argv、cmd、buf、authenticated)
一、服务器与客户端的交互Redis服务器是典型的一对多服务器程序:一个服务器可以与多个客户端建立网络连接, 每个客户端可以向服务器发送命令请求,而服务器则接收并处理客户端发送的命令请求,并向客户端返回命令回复 Redis服务器通过使用由I/O多路复用技术实现的文件事件处理器,Redis服务器使用单线程单进程的 方式来处理命令请求,并与多个客户端进行网络通信clients属性stru...原创 2019-11-29 22:19:40 · 853 阅读 · 0 评论 -
Redis(设计与实现):32---客户端之客户端的创建与关闭(client-output-buffer-limit选项、Lua伪客户端(lua_client属性)、AOF伪客户端)
一、普通客户端的创建创建的过程:如果客户端是通过网络连接与服务器进行连接的普通客户端,那么在客户端使用connect 函数连接到服务器时,服务器就会调用连接事件处理器,为客户端创建相应的客户端状态,并将这个新的客户端状态添加到服务器状态结构clients链表的末尾 举个例子,假设当前有c1和c2两个普通客户端正在连接服务器,那么当一个新的普通客 户端c3连接到服务器之后,服务器会将c3所对应...原创 2019-11-29 22:32:49 · 502 阅读 · 0 评论 -
Redis(设计与实现):33---服务端之命令请求的解析执行过程
一个命令请求从发送到获得回复的过程中,客户端和服务器需要完成一系列操作。举个例子,如果我们使用客户端执行以下命令:那么从客户端发送SET KEY VALUE命令到获得回复OK期间,客户端和服务器共需要执行以下操作: ①客户端向服务器发送命令请求SET KEY VALUE ②服务器接收并处理客户端发来的命令请求SET KEY VALUE,在数据库中进行设置操作,并产生命令回复OK ...原创 2019-11-30 21:14:27 · 431 阅读 · 0 评论 -
Redis(设计与实现):34---服务端之serverCron函数
serverCron函数Redis服务器中的serverCron函数默认每隔100毫秒执行一次,这个函数负责管理服务器的资源,并保持服务器自身的良好运转 本文接下来的内容将对serverCron函数执行的操作进行完整介绍,并介绍redisServer结构 (服务器状态)中和serverCron函数有关的属性一、更新服务器时间缓存Redis服务器中有不少功能需要获取系统的当前时间,而每次...原创 2019-11-30 21:34:07 · 419 阅读 · 0 评论 -
Redis(设计与实现):35---服务端之服务器的初始化(initServerConfig函数、initServer函数)
一个Redis服务器从启动到能够接受客户端的命令请求,需要经过一系列的初始化和设置过程,比如初始化服务器状态,接受用户指定的服务器配置,创建相应的数据结构和网络连接等等,本文接下来的内容将对服务器的整个初始化过程进行详细的介绍一、初始化服务器状态结构(initServerConfig函数)初始化服务器的第一步就是创建一个struct redisServer类型的实例变量server作为服务器...原创 2019-11-30 21:34:26 · 696 阅读 · 0 评论 -
Redis(设计与实现):36---复制的概念
一、复制的概念在Redis中,用户可以通过执行SLAVEOF命令或者设置slaveof选项,让一个服务器去复制(replicate)另一个服务器 关于复制的特性和用法还有很多,Redis官方网站上的《复制》文档 (https://redis.io/topics/replication)已经做了很详细的介绍二、主服务器、从服务器我们称呼被复制的服务器为主服务器(master) 而对主服...原创 2019-12-01 10:36:11 · 349 阅读 · 0 评论 -
Redis(设计与实现):37---复制之旧版复制功能(Redis 2.8版本之前、SYNC命令)
Redis的复制功能分为下面两个操作: 同步操作(sync):用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态 命令传播操作(command propagate):则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态 旧版复制是指在Redis 2.8版本之前的功能一、同步(SYNC命令)概念:当客户端向从服务...原创 2019-12-01 11:01:04 · 423 阅读 · 0 评论 -
Redis(设计与实现):38---复制之新版复制功能(Redis 2.8版本之后、PSYNC命令)
Redis的复制功能分为下面两个操作: 同步操作(sync):用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态 命令传播操作(command propagate):则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态 一、命令传播操作新版复制功能的命令传播操作与旧版复制功能的一致,在旧版复制功能的文件中已经介绍过...原创 2019-12-01 11:16:15 · 506 阅读 · 0 评论 -
Redis(设计与实现):39---复制之复制的详细步骤(SLAVEOF命令)
SLAVEOF命令通过向从服务器发送SLAVEOF命令,我们可以让一个从服务器去复制一个主服务器:SLAVEOF <master_ip> <master_port>一、步骤1:设置主服务器的地址和端口(masterhost、masterport属性)当客户端向从服务器发送以下命令时:从服务器首先要做的就是将客户端给定的主服务器IP地址127.0.0.1...原创 2019-12-01 13:24:52 · 960 阅读 · 0 评论 -
Redis(设计与实现):40---复制之心跳检测(REPLCONF命令、lag标志、min-slaves-to-write选项、min-slaves-max-lag选项)
REPLCONF命令在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:REPLCONF ACK <replication_offset>//其中replication_offset是从服务器当前的复制偏移量发送REPLCONF ACK命令对于主从服务器有三个作用: ①检测主从服务器的网络连接状态 ②辅助实现min-slaves选项 ③检测命...原创 2019-12-01 13:33:20 · 5700 阅读 · 2 评论