核心知识点 开篇寄语“ 1. 主从复制概述“ 既然一台宕机了无法提供服务,那多台呢?是不是就可以解决了。Redis 提供了主从模式,通过主从复制,将数据冗余一份复制到其他 Redis 服务器。 前者称为主节点 (master),后者称为从节点 (slave);数据的复制是单向的,只能由主节点到从节点。 默认情况下,每台 Redis 服务器都是主节点;且一个主节点可以有多个从节点 (或没有从节点),但一个从节点只能有一个主节点。 “ 为了保证副本数据的一致性,主从架构采用了读写分离的方式。
“ 我们可以假设主从库都可以执行写指令,假如对同一份数据分别修改了多次,每次修改发送到不同的主从实例上,就导致是实例的副本数据不一致了。 如果为了保证数据一致,Redis 需要加锁,协调多个实例的修改,Redis 自然不会这么干! “
2. 搭建主从复制主从复制的开启,完全是在从节点发起的,不需要我们在主节点做任何事情。 “ 可以通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系。 在从节点开启主从复制,有 3 种方式:
比如假设现在有实例 1(172.16.88.1)、实例 2(172.16.88.2)和实例 3 (172.16.88.3),在实例 2 和实例 3 上分别执行以下命令,实例 2 和 实例 3 就成为了实例 1 的从库,实例 1 成为 Master。 replicaof 172.16.88.1 6379 3. 主从复制原理主从库模式一旦采用了读写分离,所有数据的写操作只会在主库上进行,不用协调三个实例。 主库有了最新的数据后,会同步给从库,这样,主从库的数据就是一致的。 “ 65 哥你问题咋这么多,同步分为三种情况:
主从库第一次全量复制“ 主从库第一次复制过程大体可以分为 3 个阶段:连接建立阶段(即准备阶段)、主库同步数据到从库阶段、发送同步期间新写命令到从库阶段; 直接上图,从整体上有一个全局观的感知,后面具体介绍。 建立连接该阶段的主要作用是在主从节点之间建立连接,为数据全量同步做好准备。从库会和主库建立连接,从库执行 replicaof 并发送 psync 命令并告诉主库即将进行同步,主库确认回复后,主从库间就开始同步了。 “ 在从节点的配置文件中的 replicaof 配置项中配置了主节点的 IP 和 port 后,从节点就知道自己要和那个主节点进行连接了。 从节点内部维护了两个字段,masterhost 和 masterport,用于存储主节点的 IP 和 port 信息。 从库执行
主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到响应后,会记录下这两个参数。 FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库。 主库同步数据给从库第二阶段 master 执行 从库收到 RDB 文件后保存到磁盘,并清空当前数据库的数据,再加载 RDB 文件数据到内存中。 发送新写命令到从库第三阶段 从节点加载 RDB 完成后,主节点将 replication buffer 缓冲区的数据发送到从节点,Slave 接收并执行,从节点同步至主节点相同的状态。 “ 主库不会被阻塞,Redis 作为唯快不破的男人,怎么会动不动就阻塞呢。 在生成 RDB 文件之后的写操作并没有记录到刚刚的 RDB 文件中,为了保证主从库数据的一致性,所以主库会在内存中使用一个叫 replication buffer 记录 RDB 文件生成后的所有写操作。 “ 因为从库在通过 “ 一个在 master 端上创建的缓冲区,存放的数据是下面三个时间内所有的 master 数据写操作。 1)master 执行 bgsave 产生 RDB 的期间的写操作; 2)master 发送 rdb 到 slave 网络传输期间的写操作; 3)slave load rdb 文件把数据恢复到内存的期间的写操作。 Redis 和客户端通信也好,和从库通信也好,Redis 都分配一个内存 buffer 进行数据交互,客户端就是一个 client,从库也是一个 client,我们每个 client 连上 Redis 后,Redis 都会分配一个专有 client buffer,所有数据交互都是通过这个 buffer 进行的。 Master 先把数据写到这个 buffer 中,然后再通过网络发送出去,这样就完成了数据交互。 不管是主从在增量同步还是全量同步时,master 会为其分配一个 buffer ,只不过这个 buffer 专门用来传播写命令到从库,保证主从数据一致,我们通常把它叫做 replication buffer。 replication buffer 太小会引发的问题: replication buffer 由 client-output-buffer-limit slave 设置,当这个值太小会导致主从复制连接断开。 1)当 master-slave 复制连接断开,master 会释放连接相关的数据。replication buffer 中的数据也就丢失了,此时主从之间重新开始复制过程。 2)还有个更严重的问题,主从复制连接断开,导致主从上出现重新执行 bgsave 和 rdb 重传操作无限循环。 当主节点数据量较大,或者主从节点之间网络延迟较大时,可能导致该缓冲区的大小超过了限制,此时主节点会断开与从节点之间的连接; 这种情况可能引起全量复制 -> replication buffer 溢出导致连接中断 -> 重连 -> 全量复制 -> replication buffer 缓冲区溢出导致连接中断……的循环。 具体详情:[top redis headaches for devops – replication buffer] 因而推荐把 replication buffer 的 hard/soft limit 设置成 512M。
“ 这个问题问的好,原因如下:
增量复制“ 在 Redis 2.8 之前,如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。 从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。 增量复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。 repl_backlog_buffer 断开重连增量复制的实现奥秘就是 master 使用 master 收到写操作,偏移量则会增加。从库持续执行同步的写指令后,在 正常情况下,这两个偏移量基本相等。在网络断连阶段,主库可能会收到新的写操作命令,所以 当主从断开重连后,slave 会先发送 psync 命令给 master,同时将自己的 master 只需要把 增量复制执行流程如下图: “ 我们要想办法避免这个情况,一旦被覆盖就会执行全量复制。我们可以调整 repl_backlog_size 这个参数用于控制缓冲区大小。计算公式: repl_backlog_buffer = second * write_size_per_second
例如,如果主服务器平均每秒产生 1 MB 的写数据,而从服务器断线之后平均要 5 秒才能重新连接上主服务器,那么复制积压缓冲区的大小就不能低于 5 MB。 为了安全起见,可以将复制积压缓冲区的大小设为 基于长连接的命令传播“ 当主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,使用长连接的目的就是避免频繁建立连接导致的开销。 在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING 和 REPLCONF ACK。 主->从:PING每隔指定的时间,主节点会向从节点发送 PING 命令,这个 PING 命令的作用,主要是为了让从节点进行超时判断。 从->主:REPLCONF ACK在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:
其中 replication_offset 是从服务器当前的复制偏移量。发送 REPLCONF ACK 命令对于主从服务器有三个作用:
如何确定执行全量同步还是部分同步?在 Redis 2.8 及以后,从节点可以发送 psync 命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制。本文以 Redis 2.8 及之后的版本为例。 关键就是
一个从库如果和主库断连时间过长,造成它在主库 总结下 每个从库会记录自己的 在和主库重连进行恢复时,从库会通过 psync 命令把自己记录的 replication buffer 和 repl_backlog
总的来说,
如图所示: 4. 主从应用问题4.1 读写分离的问题数据过期问题 “ 这个问题问得好,为了主从节点的数据一致性,从节点不会主动删除数据。我们知道 Redis 有两种删除策略:
“ Redis 3.2 开始,通过从节点读取数据时,先判断数据是否已过期。如果过期则不返回客户端,并且删除数据。 4.2 单机内存大小限制如果 Redis 单机内存达到 10GB,一个从节点的同步时间在几分钟的级别;如果从节点较多,恢复的速度会更慢。如果系统的读负载很高,而这段时间从节点无法提供服务,会对系统造成很大的压力。 如果数据量过大,全量复制阶段主节点 fork + 保存 RDB 文件耗时过大,从节点长时间接收不到数据触发超时,主从节点的数据同步同样可能陷入全量复制->超时导致复制中断->重连->全量复制->超时导致复制中断……的循环。 此外,主节点单机内存除了绝对量不能太大,其占用主机内存的比例也不应过大:最好只使用 50% - 65% 的内存,留下 30%-45% 的内存用于执行 bgsave 命令和创建复制缓冲区等。 总结
|
|