承接网站建设广告语,广州市平安建设 网站,做聚美优品网站得多少钱,化妆品营销推广方案Redis ⽀持 RDB 和 AOF 两种持久化机制#xff0c;持久化功能有效地避免因进程退出造成数据丢失问题#xff0c; 当下次重启时利⽤之前持久化的⽂件即可实现数据恢复。
目录
第四章 持久化
4.1 RDB
4.1.1 触发机制
4.1.2 流程说明
4.1.3 RDB ⽂件的处理
4.1.4 RDB 的优… Redis ⽀持 RDB 和 AOF 两种持久化机制持久化功能有效地避免因进程退出造成数据丢失问题 当下次重启时利⽤之前持久化的⽂件即可实现数据恢复。
目录
第四章 持久化
4.1 RDB
4.1.1 触发机制
4.1.2 流程说明
4.1.3 RDB ⽂件的处理
4.1.4 RDB 的优缺点
4.2 AOF
4.2.1 使⽤ AOF
4.2.2 命令写⼊
4.2.3 ⽂件同步
4.2.4 重写机制
4.2.5 启动时数据恢复
4.3 本章重点回顾
第五章 Redis 事务
5.1 什么是事务
5.2 事务操作
第六章 主从复制
6.1 配置
6.2 拓扑
6.3 原理 第四章 持久化
4.1 RDB RDB 持久化是把当前进程数据⽣成快照保存到硬盘的过程触发 RDB 持久化过程分为⼿动触发和 ⾃动触发。
4.1.1 触发机制
⼿动触发分别对应 save 和 bgsave 命令 • save 命令阻塞当前 Redis 服务器直到 RDB 过程完成为⽌对于内存⽐较⼤的实例造成⻓时间 阻塞基本不采⽤。 • bgsave 命令Redis 进程执⾏ fork 操作创建⼦进程RDB 持久化过程由⼦进程负责完成后⾃动 结束。阻塞只发⽣在 fork 阶段⼀般时间很短。
Redis 内部的所有涉及 RDB 的操作都采⽤类似 bgsave 的⽅式。 除了⼿动触发之外Redis 运⾏⾃动触发 RDB 持久化机制这个触发机制才是在实战中有价值的。 1. 使⽤ save 配置。如 save m n 表⽰ m 秒内数据集发⽣了 n 次修改⾃动 RDB 持久化。 2. 从节点进⾏全量复制操作时主节点⾃动进⾏ RDB 持久化随后将 RDB ⽂件内容发送给从结点。 3. 执⾏ shutdown 命令关闭 Redis 时执⾏ RDB 持久化。 4.1.2 流程说明
bgsave 是主流的 RDB 持久化⽅式下⾯根据图 了解它的运作流程。 1. 执⾏ bgsave 命令Redis ⽗进程判断当前进是否存在其他正在执⾏的⼦进程如 RDB/AOF ⼦进 程如果存在 bgsave 命令直接返回。
2. ⽗进程执⾏ fork 创建⼦进程fork 过程中⽗进程会阻塞通过 info stats 命令查看 latest_fork_usec 选项可以获取最近⼀次 fork 操作的耗时单位为微秒。
3. ⽗进程 fork 完成后bgsave 命令返回 Background saving started 信息并不再阻塞⽗进程可 以继续响应其他命令。
4. ⼦进程创建 RDB ⽂件根据⽗进程内存⽣成临时快照⽂件完成后对原有⽂件进⾏原⼦替换。执 ⾏ lastsave 命令可以获取最后⼀次⽣成 RDB 的时间对应 info 统计的 rdb_last_save_time 选 项。
5. 进程发送信号给⽗进程表⽰完成⽗进程更新统计信息。 4.1.3 RDB ⽂件的处理 保存RDB ⽂件保存再 dir 配置指定的⽬录默认 /var/lib/redis/下⽂件名通过 dbfilename 配置默认 dump.rdb指定。可以通过执⾏ config set dir {newDir} 和 config set dbfilename {newFilename} 运⾏期间动态执⾏当下次运⾏时 RDB ⽂件会保存到新⽬录。 压缩Redis 默认采⽤ LZF 算法对⽣成的 RDB ⽂件做压缩处理压缩后的⽂件远远⼩于内存⼤⼩默认开启可以通过参数 config set rdbcompression {yes|no} 动态修改。 虽然压缩 RDB 会消耗 CPU但可以⼤幅降低⽂件的体积⽅便保存到硬盘或通过⽹络发送到 从节点因此建议开启。 校验如果 Redis 启动时加载到损坏的 RDB ⽂件会拒绝启动。这时可以使⽤ Redis 提供的 redis-check-dump ⼯具检测 RDB ⽂件并获取对应的错误报告。 4.1.4 RDB 的优缺点 • RDB 是⼀个紧凑压缩的⼆进制⽂件代表 Redis 在某个时间点上的数据快照。⾮常适⽤于备份全 量复制等场景。⽐如每 6 ⼩时执⾏ bgsave 备份并把 RDB ⽂件复制到远程机器或者⽂件系统中 如 hdfs⽤于灾备。 • Redis 加载 RDB 恢复数据远远快于 AOF 的⽅式。 • RDB ⽅式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运⾏都要执⾏ fork 创建⼦进 程属于重量级操作频繁执⾏成本过⾼。 • RDB ⽂件使⽤特定⼆进制格式保存Redis 版本演进过程中有多个 RDB 版本兼容性可能有⻛ 险。 4.2 AOF AOFAppend Only File持久化以独⽴⽇志的⽅式记录每次写命令重启时再重新执⾏ AOF ⽂件中的命令达到恢复数据的⽬的。AOF 的主要作⽤是解决了数据持久化的实时性⽬前已经是Redis 持久化的主流⽅式。理解掌握好 AOF 持久化机制对我们兼顾数据安全性和性能⾮常有帮助。
4.2.1 使⽤ AOF 开启 AOF 功能需要设置配置appendonly yes默认不开启。AOF ⽂件名通过 appendfilename 配置默认是 appendonly.aof设置。保存⽬录同 RDB 持久化⽅式⼀致通过 dir 配置指定。AOF 的⼯作流程操作命令写⼊append、⽂件同步sync、⽂件重写 rewrite、重启加载load如图 所⽰。 1. 所有的写⼊命令会追加到 aof_buf缓冲区中。
2. AOF 缓冲区根据对应的策略向硬盘做同步操作。
3. 随着 AOF ⽂件越来越⼤需要定期对 AOF ⽂件进⾏重写达到压缩的⽬的。
4. 当 Redis 服务器启动时可以加载 AOF ⽂件进⾏数据恢复。 4.2.2 命令写⼊ AOF 命令写⼊的内容直接是⽂本协议格式。例如 set hello world 这条命令在 AOF 缓冲区会追加如下 ⽂本
*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n 此处遵守 Redis 格式协议Redis 选择⽂本协议可能的原因⽂本协议具备较好的兼容性实现简单 具备可读性。 AOF 过程中为什么需要 aof_buf 这个缓冲区 Redis 使⽤单线程响应命令如果每次写 AOF ⽂件都直 接同步硬盘性能从内存的读写变成 IO 读写必然会下降。先写⼊缓冲区可以有效减少 IO 次数同 时Redis 还可以提供多种缓冲区同步策略让⽤⼾根据⾃⼰的需求做出合理的平衡。 4.2.3 ⽂件同步 Redis 提供了多种 AOF 缓冲区同步⽂件策略由参数 appendfsync 控制不同值的含义如表 所⽰。 系统调⽤ write 和 fsync 说明
• write 操作会触发延迟写delayed write机制。Linux 在内核提供⻚缓冲区⽤来提供硬盘 IO 性 能。write 操作在写⼊系统缓冲区后⽴即返回。同步硬盘操作依赖于系统调度机制例如缓冲区 ⻚空间写满或达到特定时间周期。同步⽂件之前如果此时系统故障宕机缓冲区内数据将丢失。
• Fsync 针对单个⽂件操作做强制硬盘同步fsync 将阻塞直到数据写⼊到硬盘。
• 配置为 always 时每次写⼊都要同步 AOF ⽂件性能很差在⼀般的 SATA 硬盘上只能⽀持⼤ 约⼏百 TPS 写⼊。除⾮是⾮常重要的数据否则不建议配置。
• 配置为 no 时由于操作系统同步策略不可控虽然提⾼了性能但数据丢失⻛险⼤增除⾮数据 重要程度很低⼀般不建议配置。
• 配置为 everysec是默认配置也是推荐配置兼顾了数据安全性和性能。理论上最多丢失 1 秒的 数据。 4.2.4 重写机制 随着命令不断写⼊ AOF⽂件会越来越⼤为了解决这个问题Redis 引⼊ AOF 重写机制压缩⽂ 件体积。AOF ⽂件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF ⽂件。 重写后的 AOF 为什么可以变⼩有如下原因 • 进程内已超时的数据不再写⼊⽂件。 • 旧的 AOF 中的⽆效命令例如 del、hdel、srem 等重写后将会删除只需要保留数据的最终版 本。 • 多条写操作合并为⼀条例如 lpush list a、lpush list b、lpush list 从可以合并为 lpush list a b c。 较⼩的 AOF ⽂件⼀⽅⾯降低了硬盘空间占⽤⼀⽅⾯可以提升启动 Redis 时数据恢复的速度。 AOF 重写过程可以⼿动触发和⾃动触发 • ⼿动触发调⽤ bgrewriteaof 命令。 • ⾃动触发根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定⾃动触发时 机。 ◦ auto-aof-rewrite-min-size表⽰触发重写时 AOF 的最⼩⽂件⼤⼩默认为 64MB。 ◦ auto-aof-rewrite-percentage代表当前 AOF 占⽤⼤⼩相⽐较上次重写时增加的⽐例。 当触发 AOF 重写时下图介绍它的运⾏流程。 1. 执⾏ AOF 重写请求。 如果当前进程正在执⾏ AOF 重写请求不执⾏。如果当前进程正在执⾏ bgsave 操作重写命令 延迟到 bgsave 完成之后再执⾏。
2. ⽗进程执⾏ fork 创建⼦进程。
3. 重写 a. 主进程 fork 之后继续响应其他命令。所有修改操作写⼊ AOF 缓冲区并根据 appendfsync 策 略同步到硬盘保证旧 AOF ⽂件机制正确。 b. ⼦进程只有 fork 之前的所有内存信息⽗进程中需要将 fork 之后这段时间的修改操作写⼊ AOF 重写缓冲区中。
4. ⼦进程根据内存快照将命令合并到新的 AOF ⽂件中。
5. ⼦进程完成重写 a. 新⽂件写⼊后⼦进程发送信号给⽗进程。 b. ⽗进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF ⽂件中。 c. ⽤新 AOF ⽂件替换⽼ AOF ⽂件。 4.2.5 启动时数据恢复 当 Redis 启动时会根据 RDB 和 AOF ⽂件的内容进⾏数据恢复如图所⽰。 Redis 根据持久化⽂件进⾏数据恢复 4.3 本章重点回顾
1. Redis 提供了两种持久化⽅案RDB 和 AOF。
2. RDB 视为内存的快照产⽣的内容更为紧凑占⽤空间较⼩恢复时速度更快。但产⽣ RDB 的开 销较⼤不适合进⾏实时持久化⼀般⽤于冷备和主从复制。
3. AOF 视为对修改命令保存在恢复时需要重放命令。并且有重写机制来定期压缩 AOF ⽂件。
4. RDB 和 AOF 都使⽤ fork 创建⼦进程利⽤ Linux ⼦进程拥有⽗进程内存快照的特点进⾏持久化 尽可能不影响主进程继续处理后续命令。 第五章 Redis 事务
5.1 什么是事务
Redis 的事务和 MySQL 的事务概念上是类似的. 都是把⼀系列操作绑定成⼀组. 让这⼀组能够批量执 ⾏. 但是注意体会 Redis 的事务和 MySQL 事务的区别:
• 弱化的原⼦性: redis 没有 回滚机制. 只能做到这些操作 批量执⾏. 不能做到 ⼀个失败就恢复到 初始状态.
• 不保证⼀致性: 不涉及 约束. 也没有回滚. MySQL 的⼀致性体现的是运⾏事务前和运⾏后 , 结果都 是合理有效的, 不会出现中间⾮法状态
• 不需要隔离性: 也没有隔离级别, 因为不会并发执⾏事务 (redis 单线程处理请求) .
• 不需要持久性: 是保存在内存的. 是否开启持久化, 是redis-server ⾃⼰的事情, 和事务⽆关. Redis 事务本质上是在服务器上搞了⼀个 事务队列. 每次客⼾端在事务中进⾏⼀个操作, 都会把命令先 发给服务器, 放到 事务队列 中(但是并不会⽴即执⾏)
⽽是会在真正收到 EXEC 命令之后, 才真正执⾏队列中的所有操作.
因此, Redis 的事务的功能相⽐于 MySQL 来说, 是弱化很多的. 只能保证事务中的这⼏个操作是 连续 的, 不会被别的客⼾端 加塞, 仅此⽽已.
5.2 事务操作
MULTI 开启⼀个事务. 执⾏成功返回 OK.
127.0.0.1:6379 MULTI
OKEXEC 真正执⾏事务.
127.0.0.1:6379 MULTI
OK
127.0.0.1:6379 set k1 1
QUEUED
127.0.0.1:6379 set k2 2
QUEUED
127.0.0.1:6379 set k3 3
QUEUED
127.0.0.1:6379 EXEC
1) OK
2) OK
3) OK
每次添加⼀个操作, 都会提⽰ QUEUED, 说明命令已经进⼊客⼾端的队列了.
真正执⾏ EXEC 的时候, 客⼾端才会真正把上述操作发送给服务器.
此时就可以获取到上述 key 的值了.
127.0.0.1:6379 get k1
1
127.0.0.1:6379 get k2
2
127.0.0.1:6379 get k3
3 DISCARD 放弃当前事务. 此时直接清空事务队列. 之前的操作都不会真正执⾏到.
127.0.0.1:6379 MULTI
OK
127.0.0.1:6379 set k1 1
QUEUED
127.0.0.1:6379 set k2 2
QUEUED
127.0.0.1:6379 DISCARD
OK
127.0.0.1:6379 get k1
(nil)
127.0.0.1:6379 get k2
(nil)WATCH 在执⾏事务的时候, 如果某个事务中修改的值, 被别的客⼾端修改了, 此时就容易出现数据不⼀致的问题.
# 客⼾端1 先执⾏
127.0.0.1:6379 MULTI
OK
127.0.0.1:6379 set key 100
QUEUED
# 客⼾端2 再执⾏
127.0.0.1:6379 set key 200
OK
# 客⼾端1 最后执⾏
127.0.0.1:6379 EXEC
1) OK 此时, key 的值是多少呢?? 从输⼊命令的时间看, 是客⼾端1 先执⾏的 set key 100. 客⼾端2 后执⾏的 set key 200. 但是从实际的执⾏时间看, 是客⼾端2 先执⾏的, 客⼾端1 后执⾏的. 127.0.0.1:6379 get key
100
这个时候, 其实就容易引起歧义.
因此, 即使不保证严格的隔离性, ⾄少也要告诉⽤⼾, 当前的操作可能存在⻛险. watch 命令就是⽤来解决这个问题的. watch 在该客⼾端上监控⼀组具体的 key. • 当开启事务的时候, 如果对 watch 的 key 进⾏修改, 就会记录当前 key 的 版本号. (版本号是个简单 的整数, 每次修改都会使版本变⼤. 服务器来维护每个 key 的版本号情况) • 在真正提交事务的时候, 如果发现当前服务器上的 key 的版本号已经超过了事务开始时的版本号, 就 会让事务执⾏失败. (事务中的所有操作都不执⾏). 客⼾端1 先执⾏
127.0.0.1:6379 watch k1 # 开始监控 k1
OK
127.0.0.1:6379 MULTI
OK
127.0.0.1:6379 set k1 100 # 进⾏修改, 从服务器获取 k1 的版本号是 0. 记录 k1 的版
QUEUED
127.0.0.1:6379 set k2 1000
QUEUED
只是⼊队列, 但是不提交事务执⾏.
客⼾端2 再执⾏
127.0.0.1:6379 set k1 200 # 修改成功, 使服务器端的 k1 的版本号 0 - 1
OK
客⼾端1 再执⾏
127.0.0.1:6379 EXEC # 真正执⾏修改操作, 此时对⽐版本发现, 客⼾端的 k1 的版本
(nil)
127.0.0.1:6379 get k1
200
127.0.0.1:6379 get k2
(nil)
此时说明事务已经被取消了. 这次提交的所有命令都没有执⾏. UNWATCH 取消对 key 的监控. 相当于 WATCH 的逆操作. 此处不做演⽰. 第六章 主从复制
本章节相关操作不需要记忆!!! 后续⼯作中如果⽤到了能查到即可. 重点⼤家理解流程和原理. 在分布式系统中为了解决单点问题通常会把数据复制多个副本部署到其他服务器满⾜故障恢 复和负载均衡等需求。Redis 也是如此它为我们提供了复制的功能实现了相同数据的多个 Redis 副 本。复制功能是⾼可⽤ Redis 的基础哨兵和集群都是在复制的基础上构建的。本章内容如下 • 介绍复制的使⽤⽅式如何建⽴或断开复制、安全性、只读等。 • 说明复制可⽀持的拓扑结构以及每个拓扑结构的适⽤场景。 • 分析复制的原理包括建⽴复制、全量复制、部分复制、⼼跳检测等。
如果同学⽐较少, 那么⼀个⽼师既可以进⾏授课, 也可以进⾏答疑; 但是随着学⽣多了, ⼀个⽼师也就 应付不过来了. 就需要配⼏个助教⽼师, 助教⽼师从授课⽼师这⾥获取知识, 协助授课⽼师答疑. 6.1 配置 建⽴复制 参与复制的 Redis 实例划分为主节点master和从节点slave。每个从结点只能有⼀个主节点 ⽽⼀个主节点可以同时具有多个从结点。复制的数据流是单向的只能由主节点到从节点。配置复制 的⽅式有以下三种 1. 在配置⽂件中加⼊ slaveof {masterHost} {masterPort} 随 Redis 启动⽣效。 2. 在 redis-server 启动命令时加⼊ --slaveof {masterHost} {masterPort} ⽣效。 3. 直接使⽤ redis 命令slaveof {masterHost} {masterPort} ⽣效。
接下来我们将 redis.conf 配置⽂件复制⼀份 redis-slave.conf并且修改其 daemonize 为 yes。
# By default Redis does not run as a daemon. Use yes if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize yes接下来默认启动的 redis 作为主 Redis重新通过命令⾏启动⼀个 Redis 实例作为从 Redis
# ubuntu
redis-server /etc/redis/redis-slave.conf --port 6380 --slaveof 127.0.0.1 6379
# centos
redis-server /etc/redis-slave.conf --port 6380 --slaveof 127.0.0.1 6379
注意: 修改配置主要是修改从机的配置. 主机配置不变.
通过 netstat -nlpt 确保两个 Redis 均已正确启动。
[roothost ~]# netstat -nlpt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:6380 0.0.0.0:* LISTEN
通过 redis-cli 可以连接主 Redis 实例通过 redis-cli -p 6380 连接从 Redis。并且观察复制关系。
127.0.0.1:6379 set hello world
OK
127.0.0.1:6379 get hello
world
从运⾏结果中看到复制已经⼯作了针对主节点 6379 的任何修改都可以同步到从节点 6380 中复制 过程如图所⽰。 Redis 主从节点复制过程 可以通过 info replication 命令查看复制相关状态。
1主节点 6379 复制状态信息
127.0.0.1:6379 info replication
# Replication
role:master
connected_slaves:1
slave0:ip127.0.0.1,port6380,stateonline,offset100,lag0
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:100
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:100
2从节点 6380 复制状态信息
127.0.0.1:6380 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:170
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:170
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:170 断开复制 slaveof 命令不但可以建⽴复制还可以在从节点执⾏ slaveof no one 来断开与主节点复制关系。 例如在 6380 节点上执⾏ slaveof no one 来断开复制。 断开复制主要流程 1断开与主节点复制关系。 2从节点晋升为主节点。 从节点断开复制后并不会抛弃原有数据只是⽆法再获取主节点上的数据变化。 通过 slaveof 命令还可以实现切主操作将当前从节点的数据源切换到另⼀个主节点。执⾏ slaveof {newMasterIp} {newMasterPort} 命令即可。
切主操作主要流程
1断开与旧主节点复制关系。
2与新主节点建⽴复制关系。
3删除从节点当前所有数据。
4从新主节点进⾏复制操作。 安全性 对于数据⽐较重要的节点主节点会通过设置 requirepass 参数进⾏密码验证这时所有的客⼾ 端访问必须使⽤ auth 命令实⾏校验。从节点与主节点的复制连接是通过⼀个特殊标识的客⼾端来完 成因此需要配置从节点的
masterauth 参数与主节点密码保持⼀致这样从节点才可以正确地连接到 主节点并发起复制流程。
只读 默认情况下从节点使⽤ slave-read-onlyyes 配置为只读模式。由于复制只能从主节点到从节 点对于从节点的任何修改主节点都⽆法感知修改从节点会造成主从数据不⼀致。所以建议线上不 要修改从节点的只读模式。
传输延迟 主从节点⼀般部署在不同机器上复制时的⽹络延迟就成为需要考虑的问题Redis 为我们提供 了 repl-disable-tcp-nodelay 参数⽤于控制是否关闭 TCP_NODELAY默认为 no即开启 tcp-nodelay 功能说明如下 • 当关闭时主节点产⽣的命令数据⽆论⼤⼩都会及时地发送给从节点这样主从之间延迟会变⼩ 但增加了⽹络带宽的消耗。适⽤于主从之间的⽹络环境良好的场景如同机房部署。 • 当开启时主节点会合并较⼩的 TCP 数据包从⽽节省带宽。默认发送时间间隔取决于 Linux 的内 核⼀般默认为 40 毫秒。这种配置节省了带宽但增⼤主从之间的延迟。适⽤于主从⽹络环境复杂 的场景如跨机房部署。 6.2 拓扑 Redis 的复制拓扑结构可以⽀持单层或多层复制关系根据拓扑复杂性可以分为以下三种⼀主⼀ 从、⼀主多从、树状主从结构。
⼀主⼀从结构 ⼀主⼀从结构是最简单的复制拓扑结构⽤于主节点出现宕机时从节点提供故障转移⽀持如图 所⽰。当应⽤写命令并发量较⾼且需要持久化时可以只在从节点上开启 AOF这样既可以保证数据 安全性同时也避免了持久化对主节点的性能⼲扰。但需要注意的是当主节点关闭持久化功能时如 果主节点宕机要避免⾃动重启操作。 ⼀主多从结构 ⼀主多从结构星形结构使得应⽤端可以利⽤多个从节点实现读写分离如图所⽰。对于 读⽐重较⼤的场景可以把读命令负载均衡到不同的从节点上来分担压⼒。同时⼀些耗时的读命令可 以指定⼀台专⻔的从节点执⾏避免破坏整体的稳定性。对于写并发量较⾼的场景多个从节点会导 致主节点写命令的多次发送从⽽加重主节点的负载。 树形主从结构 树形主从结构分层结构使得从节点不但可以复制主节点数据同时可以作为其他从节点的主 节点继续向下层复制。通过引⼊复制中间层可以有效降低住系欸按负载和需要传送给从节点的数据 量如图所⽰。数据写⼊节点 A 之后会同步给 B 和 C 节点B 节点进⼀步把数据同步给 D 和 E 节 点。当主节点需要挂载等多个从节点时为了避免对主节点的性能⼲扰可以采⽤这种拓扑结构。 6.3 原理
复制过程 如图所⽰下⾯详细介绍建⽴复制的完整流程。从图中可以看出复制过程⼤致分为 6 个过程 1保存主节点master的信息。
开始配置主从同步关系之后从节点只保存主节点的地址信息此时建⽴复制流程还没有开始 在从节点 6380 执⾏ info replication 可以看到如下信息
master_host: 127.0.0.1
master_port: 6379
master_link_status: down从统计信息可以看出主节点的 ip 和 port 被保存下来但是主节点的连接状态 master_link_status是下线状态。
2从节点slave内部通过每秒运⾏的定时任务维护复制相关逻辑当定时任务发现存在新的主节 点后会尝试与主节点建⽴基于 TCP 的⽹络连接。如果从节点⽆法建⽴连接定时任务会⽆限重试直 到连接成功或者⽤⼾停⽌主从复制。
3发送 ping 命令。连接建⽴成功之后从节点通过 ping 命令确认主节点在应⽤层上是⼯作良好的。 如果 ping 命令的结果 pong 回复超时从节点会断开 TCP 连接等待定时任务下次重新建⽴连接。
4权限验证。如果主节点设置了 requirepass 参数则需要密码验证从节点通过配置 masterauth 参数来设置密码。如果验证失败则从节点的复制将会停⽌。
5同步数据集。对于⾸次建⽴复制的场景主节点会把当前持有的所有数据全部发送给从节点这步 操作基本是耗时最⻓的所以⼜划分称两种情况全量同步和部分同步下⼀节重点介绍。
6命令持续复制。当从节点复制了主节点的所有数据之后针对之后的修改命令主节点会持续的把 命令发送给从节点从节点执⾏修改命令保证主从数据的⼀致性。 数据同步 psync
Redis 使⽤ psync 命令完成主从数据同步同步过程分为全量复制和部分复制。 • 全量复制⼀般⽤于初次复制场景Redis 早期⽀持的复制功能只有全量复制它会把主节点全部 数据⼀次性发送给从节点当数据量较⼤时会对主从节点和⽹络造成很⼤的开销。 • 部分复制⽤于处理在主从复制中因⽹络闪断等原因造成的数据丢失场景当从节点再次连上主节 点后如果条件允许主节点会补发数据给从节点。因为补发的数据远⼩于全量数据可以有效避 免全量复制的过⾼开销。
PSYNC 的语法格式
PSYNC replicationid offset
如果 replicationid 设为 ? 并且 offset 设为 -1 此时就是在尝试进⾏全量复制.
如果 replicationid offset 设为了具体的数值, 则是尝试进⾏部分复制. 1. replicationid/replid (复制id)
主节点的复制 id. 主节点重新启动, 或者从节点晋级成主节点, 都会⽣成⼀个 replicationid. (同⼀个节 点, 每次重启, ⽣成的 replicationid 也会变化).
从节点在和主节点建⽴连接之后, 就会获取到主节点的 replicationid.
通过 info replication 即可看到 replicationid
127.0.0.1:6379 info replication
# Replication
role:master
connected_slaves:0
master_replid:1da596acecf5a34b4b2aae45bd35be785691ae69
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0关于 master_replid 和 master_replid2 每个节点需要记录两组 master_replid . 这个设定解决的问题场景是这样的: ⽐如当前有两个节点 A 和 B, A 为 master, B 为 slave. 此时 B 就会记录 A 的 master_replid. 如果⽹络出现抖动, B 以为 A 挂了, B ⾃⼰就会成为主节点. 于是 B 给⾃⼰分配了新的 master_replid. 此时就会使⽤ master_replid2 来保存之前 A 的 master_replid. • 后续如果⽹络恢复了, B 就可以根据 master_replid2 找回之前的主节点. • 后续如果⽹络没有恢复, B 就按照新的 master_replid ⾃成⼀派, 继续处理后续的数据. 2. offset (偏移量) 参与复制的主从节点都会维护⾃⾝复制偏移量。主节点master在处理完写⼊命令后会把命令的 字节⻓度做累加记录统计信息在 info replication 中的 master_repl_offset 指标中。
127.0.0.1:6379 info replication
# Replication
role:master
...
master_repl_offset:1055130
从节点slave每秒钟上报⾃⾝的复制偏移量给主节点因此主节点也会保存从节点的复制偏移量 统计指标如下
127.0.0.1:6379 info replication
connected_slaves:1
slave0:ip127.0.0.1,port6380,stateonline,offset1055214,lag1
...
从节点在接受到主节点发送的命令后也会累加记录⾃⾝的偏移量。统计信息在 info replication 中的 slave_repl_offset 指标中
127.0.0.1:6380 info replication
# Replication
role:slave
...
slave_repl_offset:1055214复制偏移量的维护如图所⽰。通过对⽐主从节点的复制偏移量可以判断主从节点数据是否⼀致。 这个偏移量, 就相当于 学习进度. ⽐如⽼师这边准备了 10 个课件的内容. 助教要想给同学答疑, 也就需要学习完这 10 个课件的内容. 这 个偏移量就是当前助教学到了第⼏个课件了. ✍ replid offset 共同标识了⼀个 数据集. 如果两个节点, 他们的 replid 和 offset 都相同, 则这两个节点上持有的数据, 就⼀定相同. psync 运⾏流程 1从节点发送 psync 命令给主节点replid 和 offset 的默认值分别是 ? 和 -1.
2主节点根据 psync 参数和⾃⾝数据情况决定响应结果 • 如果回复 FULLRESYNC replid offset则从节点需要进⾏全量复制流程。 • 如果回复 CONTINEU从节点进⾏部分复制流程。 • 如果回复 -ERR说明 Redis 主节点版本过低不⽀持 psync 命令。从节点可以使⽤ sync 命令进⾏ 全量复制。 • psync ⼀般不需要⼿动执⾏. Redis 会在主从复制模式下⾃动调⽤执⾏. • sync 会阻塞 redis server 处理其他请求. psync 则不会. 全量复制 全量复制是 Redis 最早⽀持的复制⽅式也是主从第⼀次建⽴复制时必须经历的阶段。全量复制的运 ⾏流程如图所⽰。 1从节点发送 psync 命令给主节点进⾏数据同步由于是第⼀次进⾏复制从节点没有主节点的运 ⾏ ID 和复制偏移量所以发送 psync ? -1。
2主节点根据命令解析出要进⾏全量复制回复 FULLRESYNC 响应。
3从节点接收主节点的运⾏信息进⾏保存。
4主节点执⾏ bgsave 进⾏ RDB ⽂件的持久化。
5从节点发送 RDB ⽂件给从节点从节点保存 RDB 数据到本地硬盘。
6主节点将从⽣成 RDB 到接收完成期间执⾏的写命令写⼊缓冲区中等从节点保存完 RDB ⽂件 后主节点再将缓冲区内的数据补发给从节点补发的数据仍然按照 rdb 的⼆进制格式追加写⼊到收 到的 rdb ⽂件中. 保持主从⼀致性。
7从节点清空⾃⾝原有旧数据。
8从节点加载 RDB ⽂件得到与主节点⼀致的数据。
9如果从节点加载 RDB 完成之后并且开启了 AOF 持久化功能它会进⾏ bgrewrite 操作得到最 近的 AOF ⽂件。
通过分析全量复制的所有流程我们会发现全量复制是⼀件⾼成本的操作主节点 bgsave 的时间 RDB 在⽹络传输的时间从节点清空旧数据的时间从节点加载 RDB 的时间等。所以⼀般应该尽可能 避免对已经有⼤量数据集的 Redis 进⾏全量复制。 有磁盘复制 vs ⽆磁盘复制(diskless) 默认情况下, 进⾏全量复制需要主节点⽣成 RDB ⽂件到主节点的磁盘中, 再把磁盘上的 RDB ⽂件通过发送给从节点. Redis 从 2.8.18 版本开始⽀持⽆磁盘复制. 主节点在执⾏ RDB ⽣成流程时, 不会⽣成 RDB ⽂ 件到磁盘中了, ⽽是直接把⽣成的 RDB 数据通过⽹络发送给从节点. 这样就节省了⼀系列的写 硬盘和读硬盘的操作开销. 部分复制 部分复制主要是 Redis 针对全量复制的过⾼开销做出的⼀种优化措施使⽤ psync replicationId offset 命令实现。当从节点正在复制主节点时如果出现⽹络闪断或者命令丢失等异常情况时从节点 会向主节点要求补发丢失的命令数据如果主节点的复制积压缓冲区存在数据则直接发送给从节点 这样就可以保持主从节点复制的⼀致性。补发的这部分数据⼀般远远⼩于全量数据所以开销很⼩。 整体流程如图所⽰。 图部分复制过程 1当主从节点之间出现⽹络中断时如果超过 repl-timeout 时间主节点会认为从节点故障并终端 复制连接。
2主从连接中断期间主节点依然响应命令但这些复制命令都因⽹络中断⽆法及时发送给从节点所 以暂时将这些命令滞留在复制积压缓冲区中。
3当主从节点⽹络恢复后从节点再次连上主节点。
4从节点将之前保存的 replicationId 和 复制偏移量作为 psync 的参数发送给主节点请求进⾏部分 复制。
5主节点接到 psync 请求后进⾏必要的验证。随后根据 offset 去复制积压缓冲区查找合适的数据 并响应 CONTINUE 给从节点。
6主节点将需要从节点同步的数据发送给从节点最终完成⼀致性。
如果某个课件传输失败了, 助教可以单独要这个缺失的课件. 复制积压缓冲区 复制积压缓冲区是保存在主节点上的⼀个固定⻓度的队列默认⼤⼩为 1MB当主节点有连接的从节 点slave时被创建这时主节点master响应写命令时不但会把命令发送给从节点还会写⼊ 复制积压缓冲区如图所⽰。 由于缓冲区本质上是先进先出的定⻓队列所以能实现保存最近已复制数据的功能⽤于部分复制和 复制命令丢失的数据补救。复制缓冲区相关统计信息可以通过主节点的 info replication 中
127.0.0.1:6379 info replication
# Replication
role:master
...
repl_backlog_active:1 // 开启复制缓冲区
repl_backlog_size:1048576 // 缓冲区最⼤⻓度
repl_backlog_first_byte_offset:7479 // 起始偏移量计算当前缓冲区可⽤范围
repl_backlog_histlen:1048576 // 已保存数据的有效⻓度
根据统计指标可算出复制积压缓冲区内的可⽤偏移量范围[repl_backlog_first_byte_offset, repl_backlog_first_byte_offset repl_backlog_histlen]。
这个相当于⼀个基于数组实现的环形队列. 上述区间中的值就是 数组下标 . 如果当前从节点需要的数据, 已经超出了主节点的积压缓冲区的范围, 则⽆法进⾏部分复制, 只 能全量复制了. 实时复制 主从节点在建⽴复制连接后主节点会把⾃⼰收到的 修改操作 , 通过 tcp ⻓连接的⽅式, 源源不断的传 输给从节点. 从节点就会根据这些请求来同时修改⾃⾝的数据. 从⽽保持和主节点数据的⼀致性. 另外, 这样的⻓连接, 需要通过⼼跳包的⽅式来维护连接状态. (这⾥的⼼跳是指应⽤层⾃⼰实现的⼼跳, ⽽不是 TCP ⾃带的⼼跳).
1主从节点彼此都有⼼跳检测机制各⾃模拟成对⽅的客⼾端进⾏通信。
2主节点默认每隔 10 秒对从节点发送 ping 命令判断从节点的存活性和连接状态。
3从节点默认每隔 1 秒向主节点发送 replconf ack {offset} 命令给主节点上报⾃⾝当前的复制偏移 量。
如果主节点发现从节点通信延迟超过 repl-timeout 配置的值默认 60 秒则判定从节点下线断 开复制客⼾端连接。从节点恢复连接后⼼跳机制继续进⾏。 6.4 本章重点回顾
主从复制解决的问题:
单点问题. 1. 单个 redis 节点, 可⽤性不⾼. 2. 单个 redis 节点, 性能有限.
主从复制的特点: 1. Redis 通过复制功能实现主节点的多个副本。 2. 主节点⽤来写, 从节点⽤来读. 这样做可以降低主节点的访问压⼒. 3. 复制⽀持多种拓扑结构可以在适当的场景选择合适的拓扑结构。 4. 复制分为全量复制, 部分复制和实时复制。 5. 主从节点之间通过⼼跳机制保证主从节点通信正常和数据⼀致性。
主从复制配置的过程: 1. 主节点配置不需要改动. 2. 从节点在配置⽂件中加⼊ slaveof 主节点ip 主节点端⼝ 的形式即可.
主从复制的缺点: 1. 从机多了, 复制数据的延时⾮常明显. 2. 主机挂了, 从机不会升级成主机. 只能通过⼈⼯⼲预的⽅式恢复.