主从架构能够说是互联网必备的架构了,第一是为了保证服务的高可用,第二是为了实现读写分离,你可能熟悉咱们经常使用的 MySQL 数据库的主从架构,对于咱们 redis 来讲也不意外,redis 数据库也有各类各样的主从架构方式,在主从架构中会涉及到主节点与从节点之间的数据同步,这个数据同步的过程在 redis 中叫作复制,这在篇文章中,咱们详细的聊一聊 redis 的复制技术和主从架构 ,本文主要有如下内容:redis
主从架构环境搭建数据库
主从架构的断开安全
复制技术的原理服务器
心跳检测网络
主从拓扑架构架构
redis 的实例在默认的状况下都是主节点,因此咱们须要修改一些配置来搭建主从架构,redis 的主从架构搭建仍是比较简单的,redis 提供了三种方式来搭建主从架构,在后面咱们将就介绍,在介绍以前咱们要先了解主从架构的特性:在主从架构中有一个主节点(master)和最少一个从节点(slave),而且数据复制是单向的,只能从主节点复制到从节点,不能由从节点到主节点。并发
主从架构的创建有如下三种方式:socket
上面三种方式均可以搭建 Redis 主从架构,咱们以第一种方式来演示,其余两种方式自行尝试,因为是演示,因此就在本地启动两个 Redis 实例,并不在多台机器上启动 redis 的实例了,咱们准备一个端口 6379 的主节点实例,准备一个端口 6480 从节点的实例,端口 6480 的 redis 实例配置文件取名为 6480.conf
而且在里面添加 slaveof 语句,在配置文件最后加入以下一条语句ide
slaveof 127.0.0.1 6379
分别启动两个 redis 实例,启动以后他们会自动创建主从关系,关于这背后的原理,咱们后面在详细的聊一聊,先来验证一下咱们的主从架构是否搭建成功,咱们先在 6379 master 节点上新增一条数据:性能
而后再 6480 slave 节点上获取该数据:
能够看出咱们在 slave 节点上已经成功的获取到了在 master 节点新增的值,说明主从架构已经搭建成功了,咱们使用 info replication 命令来查看两个节点的信息,先来看看主节点的信息
能够看出 6379 端口的实例 role 为 master,有一个正在链接的实例,还有其余运行的信息,咱们再来看看 6480 端口的 redis 实例信息
能够看出两个节点之间相互记录着对象的信息,这些信息在数据复制时候将会用到。在这里有一点须要说明一下,默认状况下 slave 节点是只读的,并不支持写入,也不建议开启写入,咱们能够验证一下,在 6480 实例上写入一条数据
127.0.0.1:6480> set x 3
提示只读,并不支持写入操做,固然咱们也能够修改该配置,在配置文件中 replica-read-only yes
配置项就是用来控制从服务器只读的,为何只能只读?由于咱们知道复制是单向的,数据只能由 master 到 slave 节点,若是在 salve 节点上开启写入的话,那么修改了 slave 节点的数据, master 节点是感知不到的,slave 节点的数据并不能复制到 master 节点上,这样就会形成数据不一致的状况,因此建议 slave 节点只读。
主从架构的断开一样是 slaveof 命令,在从节点上执行 slaveof no one 命令就能够与主节点断开追随关系,咱们在 6480 节点上执行 slaveof no one 命令
127.0.0.1:6480> slaveof no one
执行完 slaveof no one 命令以后,6480 节点的角色立马恢复成了 master ,咱们再来看看时候还和 6379 实例链接在一块儿,咱们在 6379 节点上新增一个 key-value
127.0.0.1:6379> set y 3
在 6480 节点上 get y
127.0.0.1:6480> get y
在 6480 节点上获取不到 y ,由于 6480 节点已经跟 6379 节点断开的联系,不存在主从关系了,slaveof 命令不只可以断开链接,还能切换主服务器,使用命令为 slaveof {newMasterIp} {newMasterPort}
,咱们让 6379 成为 6480 的从节点, 在 6379 节点上执行 slaveof 127.0.0.1 6480
命令,咱们在来看看 6379 的 info replication
127.0.0.1:6379> info replication
6379 节点的角色已是 slave 了,而且主节点的是 6480 ,咱们能够再看看 6480 节点的 info replication
127.0.0.1:6480> info replication
在 6480 节点上有 6379 从节点的信息,能够看出 slaveof 命令已经帮咱们完成了主服务器的切换。
redis 的主从架构好像很简单同样,咱们就执行了一条命令就成功搭建了主从架构,而且数据复制也没有问题,使用起来确实简单,可是这背后 redis 仍是帮咱们作了不少的事情,好比主从服务器之间的数据同步、主从服务器的状态检测等,这背后 redis 是如何实现的呢?接下来咱们就一块儿看看
咱们执行完 slaveof 命令以后,咱们的主从关系就创建好了,在这个过程当中, master 服务器与 slave 服务器之间须要经历多个步骤,以下图所示:
slaveof 命令背后,主从服务器大体经历了七步,其中权限验证这一步不是必须的,为了可以更好的理解这些步骤,就以咱们上面搭建的 redis 实例为例来详细聊一聊各步骤。
在 6480 的客户端向 6480 节点服务器发送 slaveof 127.0.0.1 6379
命令时,咱们会立马获得一个 OK
127.0.0.1:6480> slaveof 127.0.0.1 6379
这时候数据复制工做并无开始,数据复制工做是在返回 OK 以后才开始执行的,这时候 6480 从节点作的事情是将给定的主服务器 IP 地址 127.0.0.1 以及端口 6379 保存到服务器状态的 masterhost 属性和 masterport 属性里面
在 slaveof 命令执行完以后,从服务器会根据命令设置的 IP 地址和端口,跟主服务器建立套接字链接, 若是从服务器可以跟主服务器成功的创建 socket 链接,那么从服务器将会为这个 socket 关联一个专门用于处理复制工做的文件事件处理器,这个处理器将负责后续的复制工做,好比接受全量复制的 RDB 文件以及服务器传来的写命令。一样主服务器在接受从服务器的 socket 链接以后,将为该 socket 建立一个客户端状态,这时候的从服务器同时具备服务器和客户端两个身份,从服务器能够向主服务器发送命令请求而主服务器则会向从服务器返回命令回复。
从服务器与主服务器链接成功后,作的第一件事情就是向主服务器发送一个 ping 命令,发送 ping 命令主要有如下目的:
在发送 ping 命令以后,正常状况下主服务器会返回 pong 命令,接受到主服务器返回的 pong 回复以后就会进行下一步工做,若是没有收到主节点的 pong 回复或者超时,好比网络超时或者主节点正在阻塞没法响应命令,从服务器会断开复制链接,等待下一次定时任务的调度。
从服务器在接收到主服务器返回的 pong 回复以后,下一步要作的事情就是根据配置信息决定是否须要身份验证:
在须要身份验证的状况下,从服务器将就向主服务器发送一条 auth 命令,命令参数为从服务器 masterauth 选项的值,举个例子,若是从服务器的配置里将 masterauth 参数设置为:123456,那么从服务器将向主服务器发送 auth 123456 命令,身份验证的过程也不是一路顺风的,可能会遇到如下几种状况:
全部的错误状况都会令从服务器停止当前的复制工做,而且要从创建 socket 开始从新发起复制流程,直到身份验证经过或者从服务器放弃执行复制为止
在身份验证经过后,从服务器将执行 REPLCONF listening<port-number style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; overflow-wrap: break-word !important;">命令,向主服务器发送从服务器的监听端口号,例如在咱们的例子中从服务器监听的端口为 6480,那么从服务器将向主服务器发送 REPLCONF listening 6480 命令,主服务器接收到这个命令以后,会将端口号记录在从服务器所对应的客户端状态的 slave_listening_port 属性了,也就是咱们在 master 服务器的 info replication 里面看到的 port 值。</port-number>
数据复制是最复杂的一块了,由 psync 命令来完成,从服务器会向主服务器发送一个 psync 命令来进行数据同步,在 redis 2.8 版本之前使用的是 sync 命令,除了命令不一样以外,在复制的方式上也有很大的不一样,在 redis 2.8 版本之前使用的都是全量复制,这对主节点和网络会形成很大的开销,在 redis 2.8 版本之后,数据同步将分为全量同步和部分同步。
全量复制:通常用于初次复制场景,无论是新旧版本的 redis 在从服务器第一次与主服务链接时都将进行一次全量复制,它会把主节点的所有数据一次性发给从节点,当数据较大时,会对主节点和网络形成很大的开销,redis 的早期版本只支持全量复制,这不是一种高效的数据复制方式
redis 之因此可以支持全量复制和部分复制,主要是对 sync 命令的优化,在 redis 2.8 版本之后使用的是一个全新的 psync 命令,命令格式为:psync {runId} {offset},这两个参数的意义:
也许你对上面的 runid、offset 比较陌生,不要紧,咱们先来看看下面三个概念:
一、复制偏移量
参与复制的主从节点都会分别维护自身复制偏移量:主服务器每次向从服务器传播 N 个字节的数据时,就将本身的偏移量的值加上 N,从服务器每次接收到主服务器传播的 N个字节的数据时,将本身的偏移量值加上 N。经过对比主从服务器的复制偏移量,就能够知道主从服务器的数据是否一致,若是主从服务器的偏移量老是相同,那么主从数据一致,相反,若是主从服务器两个的偏移量并不相同,那么说明主从服务器并未处于数据一致的状态,好比在有多个从服务器时,在传输的过程当中某一个服务器离线了,以下图所示:
因为从服务器A 在数据传输时,因为网络缘由掉线了,致使偏移量与主服务器不一致,那么当从服务器A 重启而且与主服务器链接成功后,从新向主服务器发送 psync 命令,这时候数据复制应该执行全量复制仍是部分复制呢?若是执行部分复制,主服务器又如何补偿从服务器A 在断线期间丢失的那部分数据呢?这些问题的答案都在复制积压缓冲区里面
二、复制积压缓冲区
复制积压缓冲区是保存在主节点上的一个固定长度的队列,默认大小为 1MB,当主节点有链接的从节点(slave)时被建立,这时主节点(master) 响应写命令时,不但会把命令发送给从节点,还会写入复制积压缓冲区,以下图所示:
所以,主服务器的复制积压缓冲区里面会保存着一部分最近传播的写命令,而且复制积压缓冲区会为队列中的每一个字节记录相应的复制偏移量。因此当从服务器从新连上主服务器时,从服务器经过 psync 命令将本身的复制偏移量 offset 发送给主服务器,主服务器会根据这个复制偏移量来决定对从服务器执行何种数据同步操做:
三、服务器运行ID
每一个 Redis 节点启动后都会动态分配一个 40 位的十六进制字符串做为运行 ID,运行 ID 的主要做用是用来惟一识别 Redis 节点,咱们可使用 info server
命令来查看
127.0.0.1:6379> info server
这里面有一个run_id
字段就是服务器运行的ID
了解这几个概念以后,咱们一块儿来看看 psync 命令的运行流程,psync 命令运行流程以下图所示:
psync 命令的逻辑比较简单,整个流程分为两步:
一、从节点发送 psync 命令给主节点,参数 runId 是当前从节点保存的主节点运行ID,参数offset是当前从节点保存的复制偏移量,若是是第一次参与复制则默认值为 -1。
二、主节点接收到 psync 命令以后,会向从服务器返回如下三种回复中的一种:
当主节点把当前的数据同步给从节点后,便完成了复制的创建流程。可是主从服务器并不会断开链接,由于接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性。
通过上面 7 步就完成了主从服务器之间的数据同步,因为这篇文章的篇幅比较长,关于全量复制和部分复制的细节就不介绍了,全量复制就是将主节点的当前的数据生产 RDB 文件,发送给从服务器,从服务器再从本地磁盘加载,这样当文件过大时就须要特别大的网络开销,否则因为数据传输比较慢会致使主从数据延时较大,部分复制就是主服务器将复制积压缓冲区的写命令直接发送给从服务器。
心跳检测是发生在主从节点在创建复制后,它们之间维护着长链接并彼此发送心跳命令,便之后续持续发送写命令,主从心跳检测以下图所示:
主从节点彼此都有心跳检测机制,各自模拟成对方的客户端进行通讯,主从心跳检测的规则以下:
主节点根据 replconf 命令判断从节点超时时间,体如今 info replication 统 计中的 lag 信息中,咱们在主服务器上执行 info replication 命令:
127.0.0.1:6379> info replication
能够看出 slave0 字段的值最后面有一个 lag,lag 表示与从节点最后一次通讯延迟的秒数,正常延迟应该在 0 和 1 之间。若是超过 repl-timeout 配置的值(默认60秒),则断定从节点下线并断开复制客户端链接,若是从节点从新恢复,心跳检测会继续进行。
Redis 的主从拓扑结构能够支持单层或多层复制关系,根据拓扑复杂性能够分为如下三种:一主一从、一主多从、树状主从架构
一主一从结构是最简单的复制拓扑结构,咱们前面搭建的就是一主一从的架构,架构如图所示:
一主一从架构用于主节点出现宕机时从节点 提供故障转移支持,当应用写命令并发量较高且须要持久化时,能够只在从节点上开启 AOF,这样既保证数据安全性同时也避免了持久化对主节点的性能干扰。可是这里有一个坑,须要你注意,就是当主节点关闭持久化功能时, 若是主节点脱机要避免自动重启操做。由于主节点以前没有开启持久化功能自动重启后数据集为空,这时从节点若是继续复制主节点会致使从节点数据也被清空的状况,丧失了持久化的意义。安全的作法是在从节点上执行 slaveof no one 断开与主节点的复制关系,再重启主节点从而避免这一问题
一主多从架构又称为星形拓扑结构,一主多从架构以下图所示:
一主多从架构能够实现读写分离来减轻主服务器的压力,对于读占比较大的场景,能够把读命令发送到 从节点来分担主节点压力。同时在平常开发中若是须要执行一些比较耗时的读命令,如:keys、sort等,能够在其中一台从节点上执行,防止慢查询对主节点形成阻塞从而影响线上服务的稳定性。对于写并发量较高的场景,多个从节点会致使主节点写命令的屡次发送从而过分消耗网络带宽,同时也加剧了主节点的负载影响服务稳定性。
树状主从架构又称为树状拓扑架构,树状主从架构以下图所示:
树状主从架构使得从节点不但能够复制主节 数据,同时能够做为其余从节点的主节点继续向下层复制。解决了一主多从架构中的不足,经过引入复制中 间层,能够有效下降主节点负载和须要传送给从节点的数据量。如架构图中,数据写入节点A 后会同步到 B 和 C节点,B节点再把数据同步到 D 和 E节点,数据实现了一层一层的向下复制。当主节点须要挂载多个从节点时为了不对主节点的性能干扰,能够采用树状主从结构下降主节点压力。