06 RDB持久化
RDB持久化1 RDB持久化方法概念RDB持久化可将内存中的数据库状态保存到磁盘上,避免数据丢失。持久化可以手动,也可以根据服务器配置选项定期执行。 RDB持久化生成的RDB文件是一个压缩过的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态。 RDB文件的创建与载入有两个命令可以生成RDB文件: SAVE。该命令会阻塞Redis服务器进程,直到RDB文件创建完毕,期间拒绝任何命令请求。 BGSAVE。派生出一个子进程来创建RDB文件,服务器进程(父进程)继续处理命令请求。 在BGSAVE命令执行期间,服务器处理SAVE、GBSAVE、BGREWRITEAOF命令会被拒绝执行。 创建RDB文件的操作由rdb.c/rdbSave函数完成。RDB文件的载入工作在服务器启动时自动执行。另外,AOF文件的更新频率比RDB文件要高,所以: 如果服务器开启了AOF,那么优先用AOF来还原数据库。 只有在AOF关闭时,服务器才会用RDB来还原数据库。 载入RDB文件的工作由rdb.c/rdbLoad函数完成。载入RDB文件期间,服务器一直处于阻塞状态。 2 自动间隔性保存R...
07 AOF持久化
AOF持久化1 AOF持久化方法概念AOF(Append Only File)持久化,与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF保存Redis所执行的写命令来记录数据库状态。被写入AOF文件的命令都是以Redis的命令请求协议格式保存的,纯文本格式,打开即可查看。 AOF持久化的实现三个步骤。 命令追加(append)、 文件写入、 文件同步(sync) 命令追加如果打开AOF功能,服务器在执行完一个写命令后,会以协议格式将被执行的命令追加到服务器状态的aof_buf缓冲区的末尾。 12345struct redisServer { // ... sds aof_buf; // ...}; 文件写入与同步Redis的服务器进程就是一个事件循环(loop),这个循环中的文件事件负责接受客户端的请求,并向客户端发送回复,而时间事件则负责执行像serverCron函数这样的定时任务。 服务器在处理文件任务时可能会执行写命令,追加内容到aof_buf缓冲区,所以服务器在每次结束一个事件循环前,都会调用flushAppendOnlyF...
08 事务
事务1 事务简介Redis通过MULTI、EXEC、WATCH等命令实现事务(transaction)功能。事务提供一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制。在事务执行期间,服务器不会中断事务去执行其他客户端的命令请求。 事务以MULTI开始,接着是多个命令放入事务之中,最后由EXEC将这个事务提交(commit)到服务器执行。 一个事务包含了多个命令,服务器在执行事务期间,不会改去执行其它客户端的命令请求。 事务中的多个命令被一次性发送给服务器,而不是一条一条发送,这种方式被称为流水线,它可以减少客户端与服务器之间的网络通信次数从而提升性能。 Redis 最简单的事务实现方式是使用 MULTI 和 EXEC 命令将事务操作包围起来。 事务队列每个Redis客户端都有自己的事务状态,保存在客户端状态的mstate属性中: 12345678910111213141516171819202122typedef struct redisClient { multiState mstate;} redisClient;typedef struct...
09 事件与并发
事件0 概述Redis服务器是一个事件驱动程序,需要处理以下两类事件: 文件事件(file event):Redis服务器通过socket与客户端连接,文件事件就是对套接字操作的对象。服务器与客户端的通信会产生相应的文件事件,服务器监听并处理这些事件来完成一系列的网络通信操作。 时间事件(time event):Redis服务器的一些操作(如serverCron函数)需要在特定时间点执行,时间事件就是对这类定时任务的抽象。 1 文件事件原理Redis基于Reactor模式开发了自己的网络事件处理器,称为文件事件处理器,文件事件处理器以单线程方式运行。 Redis 基于Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。 文件事件处理器的四个组成部分: 套接字。当被监听的套接字准备好执行accept、read、write、close等操作时,与操作相对应的文件事件就会产生。 I/O多路复用程序。使用I/O多路复用...
10 复制
复制0 概述Redis中,用户可以执行saveof命令或设置saveof选项,让一个服务器去复制(replicate)另一个服务器。被复制的服务器叫做master,对master进行复制的服务器叫做slave。 进行复制中的master和slave应该保存相同的数据,这称作“数据库状态一致”。 一个从服务器只能有一个主服务器,并且不支持主主复制。 1 旧版复制功能的实现Redis的复制功能分为同步(sync)和命令传播(command propagate)两个操作: 同步用于将slave的数据库状态更新至master当前所处的数据库状态。 命令传播用于master的数据块状态被修改,导致和lsave的数据库状态不一致时,让两者的数据库重回一致状态。 同步复制开始时,slave会先执行同步操作,步骤如下: slave对master发送SYNC命令 master收到SYNC执行BGSAVE,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。 master的BGSAVE执行完毕后,将生成的RDB文件发送给slave,slave接收并载入这个RDB,更新自己...
11 Sentinel
SentinelSentinel(哨兵)是Redis的高可用性解决方案,由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个master以及属下的所有slave。Sentinel在被监视的master下线后,自动将其属下的某个slave升级为新的master,然后由新的master继续处理命令请求。 1 Sentinel初始化过程启动并初始化Sentinel启动一个Sentinel可以使用命令: redis-sentinel sentinel.conf 或者 redis-server sentnel.conf —sentinel 当一个Sentinel启动时,会执行以下几步: 初始化服务器 将普通Redis服务器使用的代码替换成Sentinel专用代码 初始化Sentinel状态 根据配置文件,初始化监视的master列表 创建与master的网络连接 初始化服务器Sentinel本质上是一个运行在特殊模式下的Redis服务器,它的初始化过程与普通Redis服务器并不相同: 功能 Sentinel使用情况 数据库和键值对方面的命令:S...
12 集群与分片
集群分片0 概述Redis集群是分布式的数据库方案,通过分片(sharing)来进行数据共享,并提供复制或故障转移功能。 1 节点一个Redis集群通常由多个节点(node)组成。开始时每个node都是独立的,要将其连接起来: CLUSTER MEET 启动节点一个节点就是运行在集群模式下的Redis服务器,根据cluster-endabled配置选项是否为yes来决定是否开启集群模式。 节点在集群模式下会继续使用单机模式的组件,如: 文件事件处理器 时间事件处理器 使用数据库来保存键值对数据 RDB和AOF持久化 发布与订阅 复制模块 Lua脚本 节点会继续使用redisServer结构保存服务器的状态,redisClient结构保存客户端的状态,集群模式下的数据,保存在cluster.h/clusterNode、cluster.h/clusterLink、cluster.h/clusterState结构中。 集群数据结构cluster.h/clusterNode保存了一个节点的当前状态,如节点的创建时间、名字、配置纪元、IP和端口等。每个节点都有一个自己的clus...
13 发布与订阅
发布与订阅0 概述Redis的发布与订阅功能由PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令组成。 通过执行SUBSCRIBE命令,客户端可以订阅一个或多个频道,成为这些频道的订阅者(subscriber):每当有其他客户端向被订阅的频道发送消息时,频道的所有订阅者都会收到这条消息。 客户端还可以通过PSUBSCRIBE订阅一个或多个模式:每当有其他客户端向某个频道发送消息,消息不仅会发送给这个频道的订阅者,还会发送给与这个频道相匹配的模式的订阅者。 1 频道的订阅与退订Redis将所有频道的订阅关系都保存在服务器状态的pubsub_channles字典中,键是某个被订阅的频道,值是一个链表,里面记录了所有订阅这个频道的客户端: 123struct redisServer { dict *pubsub_channels;}; 订阅频道每当客户端执行SUBSCRIBE命令时,服务器都会将客户端与被订阅的频道在pubsub_channles字典中关联: 如果频道已有其他订阅者,将当前客户端添加到订阅者链表的末尾。 如果频道未有订阅者,则在pu...
20 Lua脚本
Redis从2.6版本开始引入对Lua脚本的支持,通过在服务器中嵌入Lua环境,Redis客户端可以使用Lua脚本,直接在服务器原子地执行多个Redis命令。 EVAL命令可以直接对输入的脚本进行求值: EVAL “return ‘hello world’” 0 “hello world” EVALSHA命令可以根据脚本的SHA1校验和来对脚本进行求值,但这个命令要求校验和对应的脚本至少被EVAL命令执行过一次,或者被SCRIPT LOAD命令载入过。 20.1 创建并修改Lua环境Redis服务器创建并修改Lua环境的整个过程有以下步骤: 创建一个基础的Lua环境 载入多个函数库到Lua环境 创建全局表格redis,表格包含了对Redis进行操作的函数,如redis.call 使用Redis自制的随机函数来替换Lua原有的带有副作用的随机函数 创建排序辅助函数 创建redis.pcall函数的错误报告辅助函数,这个函数可以提供更详细的出错信息 对Lua环境中的全局变量进行保护,防止用户在执行Lua脚本时添加额外的全局变量 将完成修改的Lua环境保存到服务器状态的lua属性...
21 排序
Redis的SORT命令可以对列表键、集合键或者有序集合键的值进行排序。 21.1 SORT <key>命令的实现SORT <key> 可以对一个包含数字值的键key进行排序,假设: PRUSH numbers 3 1 2 SORT numbers 创建一个和numbers长度相同的数组,每个元素都是一个redis.h/redisSortObject结构。 遍历数组,将每个元素的obj指针指向numbers列表的各个项,构成一一对应关系。 遍历数组,将各个obj指针所指向的列表项转换为一个double类型的浮点数,并将这个浮点数保存在相应数组项的u.score属性中。 根据数组项u.score的值,对数组进行数字值排序。 遍历数组,将各个数组项的obj指针所指向的列表项作为排序结果返回给客户端。 12345678910111213typedef struct _redisSortObject { // 被排序的值 robj *obj; // 权重 union { // 排序数字值时使用 ...














