第一章 初始Redis
1.1 Redis简介
Redis 是一个远程内存数据库,它不仅性能强劲,而且还具有复制特性以及为解决问题而生 的独一无二的数据模型。Redis 提供了 5 种不同类型的数据结构,各式各样的问题都可以很自然 地映射到这些数据结构上:Redis 的数据结构致力于帮助用户解决问题,而不会像其他数据库那 样,要求用户扭曲问题来适应数据库。除此之外,通过复制、持久化(persistence)和客户端分 片(client-side sharding)等特性,用户可以很方便地将 Redis 扩展成一个能够包含数百 GB 数据、 每秒处理上百万次请求的系统。
Redis是一个速度非常快的非关系数 据库(non-relational database),它可以存储键(key)与 5 种不同类型的值(value)之间的 映射(mapping),可以将存储在内存的键值对数据持久化到硬盘,可以使用复制特性来扩 展读性能,还可以使用客户端分片来扩展写性能。
1.1.1 Redis与其他数据库的对比
1.1.2 附加特性
在使用类似 Redis 这样的内存数据库时,一个首先要考虑的问题就是“当服务器被关闭时, 服务器存储的数据将何去何从呢?”Redis 拥有两种不同形式的持久化方法,它们都可以用小而 紧凑的格式将存储在内存中的数据写入硬盘:
- 时间点转储(point-in-time dump):转储操作既可以在“指定时间段内有指定数量的写操作执行”这一条件被满足时执行, 又可以通过调用两条转储到硬盘(dump-to-disk)命令中的任何一条来执行。
- 将所有修改了数据库的命令都写入一个只追加(append-only)文件里面,用户可以根据数据的重 要程度,将只追加写入设置为从不同步(sync)、每秒同步一次或者每写入一个命令就同步一次。
为了扩展 Redis 的读性能,并为 Redis 提供故障转移(failover)支持,Redis 实现了 主从复制 特性:执行复制的从服务器会连接上主服务器,接收主服务器发送的整个数据库的初始副本(copy); 之后主服务器执行的写命令,都会被发送给所有连 接着的从服务器去执行,从而实时地更新从服务器的数据集。因为从服务器包含的数据会不断地 进行更新,所以客户端可以向任意一个从服务器发送读请求,以此来避免对主服务器进行集中式 的访问。
1.2 Redis数据结构简介
第二章 Redis命令
本章主要内容:
- 字符串命令、列表命令和集合命令
- 散列命令和有序集合命令
- 发布命令与订阅命令
- 其他命令
2.1 字符串
在Redis里面,字符串可以存储以下三种类型的数据
- 字符串(byte string)
- 整数:整数的取 值范围和系统的长整数(long integer)的取值范围相同
- 浮点数:浮点数的取值范围和精度与 IEEE 754 标准的双精度浮点数(double)相同
下表为Redis中字符串的自增与自减命令
命令 | 用例和描述 |
---|---|
INCR |
INCR key-name—将键存储的值加上1 |
DECR |
DECR key-name—将键存储的值减去1 |
INCRBY |
INCRBY key-name amount—将键存储的值加上整数amount |
DECRBY |
DECRBY key-name amount—将键存储的值减去整数amount |
INCRBYFLOAT |
INCRBYFLOAT key-name amount—将键存储的值加上浮点数amount |
除了自增操作和自减操作之外,Redis 还拥有对字节串的其中一部分内容进行读取或者写入 的操作(这些操作也可以用于整数或者浮点数,但这种用法并不常见)
命令 | 用例和描述 |
---|---|
APPEND |
APPEND key-name value—将值value追加到给定键key-name当前存储的值的末尾 |
GETRANGE |
GETRANGE key-name start end— 获取一个由偏移量 start 至偏移量 end 范围内所有字符组成 的子串,包括 start 和 end 在内 |
SETRANGE |
SETRANGE key-name offset value—将从start偏移量开始的子串设置为给定值 |
GETBIT |
GETBIT key-name offset— 将字节串看作是二进制位串(bit string),并返回位串中偏移量为 offset 的二进制位的值 |
SETBIT |
SETBIT key-name offset value— 将字节串看作是二进制位串,并将位串中偏移量为 offset 的二进制位的值设置为 value |
BITCOUNT |
BITCOUNT key-name [start end]— 统计二进制位串里面值为 1 的二进制位的数量,如果给定 了可选的 start 偏移量和 end 偏移量,那么只对偏移量指定范围内的二进制位进行统计 |
BITOP |
BITOP operation dest-key key-name [key-name …]— 对一个或多个二进制位串执行包 括并(AND)、或 (OR)、异或(XOR)、非 (NOT)在内的任意一种按位运算操作(bitwise operation), 并将计算得出的结果保存在 dest-key 键里面 |
2.2 列表
Redis 的列表允许用户从序列的两端推入或者弹出元素,获取列表元 素,以及执行各种常见的列表操作。除此之外,列表还可以用来存储任务信息、最近浏览过的文章或者常用联系人信息。
命令 | 用例和描述 |
---|---|
RPUSH |
RPUSH key-name value [value …]—将一个或多个值推入列表的右端 |
LPUSH |
LPUSH key-name value [value …]—将一个或多个值推入列表的左端 |
RPOP |
RPOP key-name—移除并返回列表最右端的元素 |
LPOP |
LPOP key-name—移除并返回列表最左端的元素 |
LINDEX |
LINDEX key-name offset—返回列表中偏移量为offset的元素 |
LRANGE |
返回列表从 start 偏移量到 end 偏移量范围内的所有元素 |
LTRIM |
对列表进行修剪,只保留从start偏移量到end偏移量范围,包括两端 |
有几个列表命令可以将元素从一个列表移动到另一个列表,或者阻塞(block)执行命令的 客户端直到有其他客户端给列表添加元素为止。
命令 | 用例和描述 |
---|---|
BLPOP |
BLPOP key-name [key-name …] timeout— 从第一个非空列表中弹出位于最左端的元素, 或者在 timeout 秒之内阻塞并等待可弹出的元素出现 |
BRPOP |
BRPOP key-name [key-name …] timeout— 从第一个非空列表中弹出位于最右端的元素, 或者在 timeout 秒之内阻塞并等待可弹出的元素出现 |
RPOPLPUSH |
RPOPLPUSH source-key dest-key— 从 source-key 列表中弹出位于最右端的元素,然后 将这个元素推入 dest-key 列表的最左端,并向用户返回这个元素 |
BRPOPLPUSH |
BRPOPLPUSH source-key dest-key timeout—从source-key列表中弹出位于最右端的 元素,然后将这个元素推入 dest-key 列表的最左端,并向用户返回这个元素;如果 source-key 为空,那么在 timeout 秒之内阻塞并等待可弹出的元素出现 |
2.3 集合
Redis 的集合以无序的方式来存储多个各不相同的元素,用户可以快速地对集合执行添加 元素操作、移除元素操作以及检查一个元素是否存在于集合里。
命令 | 用例和描述 |
---|---|
SADD |
SADD key-name item [item …]— 将一个或多个元素添加到集合里面,并返回被添 加元素当中原本并不存在于集合里面的元素数量 |
SREM |
SREM key-name item [item …]— 从集合里面移除一个或多个元素,并返回被移除 元素的数量 |
SISMEMBER |
SISMEMBER key-name item—检查元素item是否存在于集合key-name里 |
SCARD |
SCARD key-name—返回集合包含的元素的数量 |
SMEMBERS |
SMEMBERS key-name—返回集合包含的所有元素 |
SRANDMEMBER |
SRANDMEMBER key-name [count]— 从集合里面随机地返回一个或多个元素。当 count 为正数时,命令返回的随机元素不会重复;当 count 为负数时,命令返回的随机元素可能会 出现重复 |
SPOP |
SPOP key-name—随机地移除集合中的一个元素,并返回被移除的元素 |
SMOVE |
SMOVE source-key dest-key item— 如果集合 source-key 包含元素 item,那么从 集合 source-key 里面移除元素 item,并将元素 item 添加到集合 dest-key 中;如果 item 被成功移除,那么命令返回 1,否则返回 0 |
通过使用上面展示的命令,我们可以将各不相同的多个元素添加到集合里面,集合真正厉害的地方在于组合 和关联多个集合。
命令 | 用例和描述 |
---|---|
SDIFF |
SDIFF key-name [key-name …]—返回那些存在于第一个集合、但不存在于其他集合中的元素(数学上的差集运算) |
SDIFFSTORE |
SDIFFSTORE dest-key key-name [key-name …]— 将那些存在于第一个集合但并不存在于其他集合中的元素(数学上的差集运算)存储到 dest-key 键里面 |
SINTER |
SINTER key-name [key-name …]— 返回那些同时存在于所有集合中的元素(数学上的交集运算) |
SINTERSTORE |
SINTERSTORE dest-key key-name [key-name …]— 将那些同时存在于所有集合的元素(数学上的交集运算)存储到 dest-key 键里面 |
SUNION |
SUNION key-name [key-name …]— 返回那些至少存在于一个集合中的元素(数学上的并集计算) |
SUNIONSTORE |
SUNIONSTORE dest-key key-name [key-name …]— 将那些至少存在于一个集合中的元素(数学上的并集计算)存储到 dest-key 键里面 |
2.4 散列
Redis 的散列可以让用户将多个键值对存储到一个 Redis 键里面。从功能上 来说,Redis 为散列值提供了一些与字符串值相同的特性,使得散列非常适用于将一些相关的数 据存储在一起。我们可以把这种数据聚集看作是关系数据库中的行,或者文档数据库中的文档。
命令 | 用例和描述 |
---|---|
HMGET |
HMGET key-name key [key …]— 从散列里面获取一个或多个键的值 |
HMSET |
HMSET key-name key value [key value …]—为散列里面的一个或多个键设置值 |
HDEL |
HDEL key-name key [key …]— 删除散列里面的一个或多个键值对,返回成功找到并删除的 键值对数量 |
HLEN |
HLEN key-name— 返回散列包含的键值对数量 |
下面列出了散列的其他几个批量操作命令,以及一些和字符串操作类似的散列命令。
命令 | 用例和描述 |
---|---|
HEXISTS |
HEXISTS key-name key—检查给定键是否存在于散列中 |
HKEYS |
HKEYS key-name—获取散列包含的所有键 |
HVALS |
HVALS key-name—获取散列包含的所有值 |
HGETALL |
HGETALL key-name—获取散列包含的所有键值对 |
HINCRBY |
HINCRBY key-name key increment—将键key存储的值加上整数increment |
HINCRBYFLOAT |
HINCRBYFLOAT key-name key increment—将键key存储的值加上浮点数increment |
2.5 有序集合
和散列存储着键与值之间的映射类似,有序集合也存储着成员与分值之间的映射,并且提供 了分值处理命令,以及根据分值大小有序地获取(fetch)或扫描(scan)成员和分值的命令。
命令 | 用例和描述 |
---|---|
ZADD |
ZADD key-name score member [score member …]—将带有给定分值的成员添加到有序集合里面 |
ZREM |
ZREM key-name member [member …]—从有序集合里面移除给定的成员,并返回被移除成员的数量 |
ZCARD |
ZCARD key-name—返回有序集合包含的成员数量 |
ZINCRBY |
ZINCRBY key-name increment member—将member成员的分值加上increment |
ZCOUNT |
ZCOUNT key-name min max—返回分值介于min和max之间的成员数量 |
ZRANK |
ZRANK key-name member—返回成员member在有序集合中的排名 |
ZSCORE |
ZSCORE key-name member—返回成员member的分值 |
ZRANGE |
ZRANGE key-name start stop [WITHSCORES]—返回有序集合中排名介于start和stop 之间的成员,如果给定了可选的 WITHSCORES 选项,那么命令会将成员的分值也一并返回 |
有序集合的范围型数据获取命令和范围型数据删除命令,以及并集命令和交集命令。
命令 | 用例和描述 |
---|---|
ZREVRANK |
ZREVRANK key-name member— 返回有序集合里成员 member 的排名,成员按照分值 从大到小排列 |
ZREVRANGE |
ZREVRANGE key-name start stop [WITHSCORES]— 返回有序集合给定排名范围内 的成员,成员按照分值从大到小排列 |
ZRANGEBYSCORE |
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]—返回 有序集合中,分值介于 min 和 max 之间的所有成员 |
ZREVRANGEBYSCORE |
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]— 获取有序集合中分值介于 min 和 max 之间的所有成员,并按照分值从大到小的顺序来返 回它们 |
ZREMRANGEBYRANK |
ZREMRANGEBYRANK key-name start stop— 移除有序集合中排名介于 start 和 stop 之间的所有成员 |
ZREMRANGEBYSCORE`` | ZREMRANGEBYSCORE key-name min max— 移除有序集合中分值介于 min 和 max 之 间的所有成员 |
ZINTERSTORE |
ZINTERSTORE dest-key key-count key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM |
ZUNIONSTORE |
ZUNIONSTORE dest-key key-count key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM |
2.6 发布订阅
发布与订阅(又称 pub/sub)的特 点是订阅者(listener)负责订阅频道(channel),发送者(publisher)负责向频道发送二进制字 符串消息(binary string message)。每当有消息被发送至给定频道时,频道的所有订阅者都会收 到消息。
命令 | 用例和描述 |
---|---|
SUBSCRIBE |
SUBSCRIBE channel [channel …]—订阅给定的一个或多个频道 |
UNSUBSCRIBE |
UNSUBSCRIBE [channel [channel …]]—退订给定的一个或多个频道,如果执行时没有给定任何频道,那么退订所有频道 |
PUBLISH |
PUBLISH channel message—向给定频道发送消息 |
PSUBSCRIBE |
PSUBSCRIBE pattern [pattern …]—订阅与给定模式相匹配的所有频道 |
PUNSUBSCRIBE |
PUNSUBSCRIBE [pattern [pattern …]]— 退订给定的模式,如果执行时没有给定任何 模式,那么退订所有模式 |
对于旧版 Redis 来说,如果一个客户端订阅了某个 或某些频道,但它读取消息的速度却不够快的话,那么不断积压的消息就会使得 Redis 输出缓冲 区的体积变得越来越大,这可能会导致 Redis 的速度变慢,甚至直接崩溃。也可能会导致 Redis 被操作系统强制杀死,甚至导致操作系统本身不可用。新版的 Redis 不会出现这种问题,因为它 会自动断开不符合 client-output-buffer-limit pubsub 配置选项要求的订阅客户端。
任何网络系统在执行操作时都可能会遇上断线情况, 而断线产生的连接错误通常会使得网络连接两端中的其中一端进行重新连接。
2.7 其他命令
2.7.1 排序
负责执行排序操作的 SORT 命令可以根据字符串、列表、集合、有序集合、散 列这 5 种键里面存储着的数据,对列表、集合以及有序集合进行排序。
使用 SORT 命令提供的选项可以实现以下功能:根据降序而不是默认的升序来排序元素; 将元素看作是数字来进行排序,或者将元素看作是二进制字符串来进行排序(比如排序字符 串’110’和’12’的结果就跟排序数字 110 和 12 的结果不一样);使用被排序元素之外的其 他值作为权重来进行排序,甚至还可以从输入的列表、集合、有序集合以外的其他地方进行 取值。
命令 | 用例和描述 |
---|---|
SORT |
SORT source-key [BY pattern] [LIMIT offset count] [GET pattern [GETpattern …]] [ASC|DESC] [ALPHA] [STORE dest-key] 根据给定的选项,对输入 列表、集合或者有序集合进行排序,然后返回或者存储排序的结果 |
2.7.2 基本的Redis事务
尽管 Redis 有几个可以在 两个键之间复制或者移动元素的命令,但却没有那种可以在两个不同类型之间移动元素的命令 (虽然可以使用 ZUNIONSTORE 命令将元素从一个集合复制到一个有序集合)。为了对相同或者不 同类型的多个键执行操作,Redis 有 5 个命令可以让用户在不被打断(interruption)的情况下对多个键执行操作,它们分别是 WATCH、MULTI、EXEC、UNWATCH 和 DISCARD。
Redis 的基本事务(basic transaction)需要用到 MULTI 命令和 EXEC 命令,这种事务可以让 一个客户端在不被其他客户端打断的情况下执行多个命令。和关系数据库那种可以在执行的过程 中进行回滚(rollback)的事务不同,在 Redis 里面,被 MULTI 命令和 EXEC 命令包围的所有命 令会一个接一个地执行,直到所有命令都执行完毕为止。当一个事务执行完毕之后,Redis 才会 处理其他客户端的命令。
2.7.3 键的过期时间
在使用 Redis 存储数据的时候,有些数据可能在某个时间点之后就不再有用了,用户可以使 用 DEL 命令显式地删除这些无用数据,也可以通过 Redis 的过期时间(expiration)特性来让一个 键在给定的时限(timeout)之后自动被删除。
对于列表、集合、散列和有序集合这样的容器(container)来说,键过期命令只能为整个键设 置过期时间,而没办法为键里面的单个元素设置过期时间。
命令 | 用例和描述 |
---|---|
PERSIST |
PERSIST key-name—移除键的过期时间 |
TTL |
TTL key-name—查看给定键距离过期还有多少秒 |
EXPIRE |
EXPIRE key-name seconds—让给定键在指定的秒数之后过期 |
EXPIREAT |
EXPIREAT key-name timestamp—将给定键的过期时间设置为给定的UNIX时间戳 |
PTTL |
PTTL key-name—查看给定键距离过期时间还有多少毫秒 |
PEXPIRE |
PEXPIRE key-name milliseconds— 让给定键在指定的毫秒数之后过期 |
PEXPIREAT |
PEXPIREAT key-name timestamp-milliseconds—将一个毫秒级精度的UNIX时间戳设置 为给定键的过期时间, |
第三章 数据安全性与性能保障
本章主要内容
- 将数据持久化到硬盘
- 将数据复制至其他机器
- 处理系统故障
- Redis 事务
- 非事务型流水线(non-transactional pipeline)
- 诊断性能问题
3.1 持久化选项
Redis 提供了两种不同的持久化方法来将数据存储到硬盘里面。一种方法叫快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里面。另一种方法叫只追加文件(append-only file, AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面。这两种持久化方法既可以同 时使用,又可以单独使用,在某些情况下甚至可以两种方法都不使用,具体选择哪种持久化方法 需要根据用户的数据以及应用来决定。
将内存中的数据存储到硬盘的一个主要原因是为了在之后重用数据,或者是为了防止系统 故障而将数据备份到一个远程位置。另外,存储在 Redis 里面的数据有可能是经过长时间计算 得出的,或者有程序正在使用 Redis 存储的数据进行计算,所以用户会希望自己可以将这些数 据存储起来以便之后使用,这样就不必再重新计算了。
1 | 通过 Homebrew 配置文件地址 |
3.1.1 快照持久化
Redis 可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。在创建快照 之后,用户可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本,还可以将快照留在原地以便重启服务器时使用。
1 | save 60 1000 |
根据配置,快照将被写入 dbfilename 选项指定的文件里面,并储存在 dir 选项指定的路径上面。如果在新的快照文件创建完毕之前,Redis、系统或者硬件这三者之中的任意一个崩溃 了,那么 Redis 将丢失最近一次创建快照之后写入的所有数据。
创建快照的方法
- 客户端可以通过向Redis发送BGSAVE命令来创建一个快照。对于支持BGSAVE命令的平台来说(基本上所有平台都支持,除了Windows平台),Redis会调用fork1来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程则继续处理命令请求。
- 客户端还可以通过向 Redis 发送 SAVE 命令来创建一个快照,接到 SAVE 命令的 Redis 服 务器在快照创建完毕之前将不再响应任何其他命令。SAVE 命令并不常用,通常只会在没有足够内存去执行 BGSAVE 命令的情况下,又或者即使等待持久化操作执行完毕也无所谓的情况下,才会使用这个命令。
- 如果用户设置了 save 配置选项,比如 save 60 10000,那么从 Redis 最近一次创建快照之后开始算起,当“60 秒之内有 10 000 次写入”这个条件被满足时,Redis 就会自动 触发 BGSAVE 命令。如果用户设置了多个 save 配置选项,那么当任意一个 save 配置 选项所设置的条件被满足时,Redis 就会触发一次 BGSAVE 命令。
- 当 Redis 通过 SHUTDOWN 命令接收到关闭服务器的请求时,或者接收到标准 TERM 信号 时,会执行一个 SAVE 命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在 SAVE 命令执行完毕之后关闭服务器。
- 当一个 Redis 服务器连接另一个 Redis 服务器,并向对方发送 SYNC 命令来开始一次复 制操作的时候,如果主服务器目前没有在执行 BGSAVE 操作,或者主服务器并非刚刚执 行完 BGSAVE 操作,那么主服务器就会执行 BGSAVE 命令。
在只使用快照持久化来保存数据时,一定要记住:如果系统真的发生崩溃,用户将丢失最近一次生成快照之后更改的所有数据。因此,快照持久化只适用于那些即使丢失一部分数据也 不会造成问题的应用程序,不能接受这种数据损失的应用程序则可以考虑使用 AOF 持久化。
几个使用快照持久化的场景
- 个人开发
- 对日志进行聚合计算
- 大数据
3.1.2 AOF持久化
AOF 持久化会将被执行的写命令写到 AOF 文件的末尾,以此来记录数据发生的变化。因此,Redis 只要从头到尾重新执行一次 AOF 文件包含的所有写命令,就可以恢复 AOF 文件所记录的数据集。
文件同步 在向硬盘写入文件时,至少会发生3件事。当调用 file.write()
方法 ( 或者其他编程语言里面的类似操作)对文件进行写入时,写入的内容首先会被存储到缓冲区,然后操作系统会在将来的某个时候将缓冲区存储的内容写入硬盘,而数据只有在被写入硬盘之后,才算是真正地保存到了硬盘里面。用户可以通过调用 file.flush()
方法来请求操作系统尽快地将缓冲区存储的数据写入硬盘里,但具体何时执行写入操作仍然由操作系统决定。除此之外,用户还可以命令操作系统将文件同步(sync)到硬盘,同步操作会一直阻塞直到指定的文件被写入硬盘为止。当同步操作执行完毕之后,即使系统出现故障也不会对被同步的文件造成任何影响。
1 | appendonly no |
3.1.3 重写/压缩 AOF 文件
AOF 持久化既可以将丢失数据的时间窗口降低至 1 秒(甚至不丢失任何数据),又可以在极短的时间内完成定期的持久化操作,那么我们有什么理由不使用 AOF 持久化呢? 因为 AOF 文件体积会不断增大。
为了解决 AOF 文件体积不断增大的问题,用户可以向 Redis 发送 BGREWRITEAOF 命令,这个命令会通过移除 AOF 文件中的冗余命令来重写(rewrite)AOF 文件,使 AOF 文件的体积变得尽可能地小。
3.2 复制
复制可以让其他服务器拥有一个不断地更新的数据副本,从而使得拥有数据副本的服务器可以用于处理客户端发送的读请求。关系数据库通常会使用一个主服务器(master)向多个从服务器(slave)发送更新,并使用从服务器来处理所有读请求。Redis 也采用了同样的方法来实现 自己的复制特性,并将其用作扩展性能的一种手段。
3.2.1 对 Redis 的复制相关选项进行配置
当从服务器连接主服务器的时候,主服务器会执行 BGSAVE 操作。 因此为了正确地使用复制特性,用户需要保证主服务器已经正确地设置了dir 选项和 dbfilename 选项,并且这两个选项所指示的路径和文件对于 Redis 进程来说都是可写的(writable)。
尽管有多个不同的选项可以控制从服务器自身的行为,但开启从服务器所必须的选项只有 slaveof一个。如果用户在启动Redis服务器的时候,指定了一个包含slaveof host port 选项的配置文件,那么 Redis 服务器将根据该选项给定的 IP 地址和端口号来连接主服务器。对于一个正在运行的Redis服务器,用户可以通过发送SLAVEOF no one命令来让服务器终止复制操作,不再接受主服务器的数据更新;也可以通过发送SLAVEOF host port命令来让服务器 开始复制一个新的主服务器。
3.2.2 Redis 复制的启动过程
从服务器在连接一个主服务器的时候,主服务器会创建一个快照文件并 将其发送至从服务器,但这只是主从复制执行过程的其中一步。
步骤 | 主服务器操作 | 从服务器操作 |
---|---|---|
1 | (等待命令进入) | 连接(或者重连接)主服务器,发送 SYNC 命令 |
2 | 开始执行 BGSAVE,并使用缓冲区记录 BGSAVE之后执行的所有写命令 | 根据配置选项来决定是继续使用现有的数据(如果有的话)来处理客户端的命令请求,还是向发送请求的客户端返回错误 |
3 | BGSAVE 执行完毕,向从服务器发送快照文件, 并在发送期间继续使用缓冲区记录被执行的写命令 | 丢弃所有旧数据(如果有的话),开始载入主服务器发来的快照文件 |
4 | 快照文件发送完毕,开始向从服务器发送存储在缓冲区里面的写命令 | 完成对快照文件的解释操作,像往常一样开始接受命令请求 |
5 | 缓冲区存储的写命令发送完毕;从现在开始, 每执行一个写命令,就向从服务器发送相同的 写命令 | 执行主服务器发来的所有存储在缓冲区里面的写命 令;并从现在开始,接收并执行主服务器传来的每个写命令 |