1 简介
这篇文章主要讲述 Redis 的主从复制功能. 会依次从环境搭建, 功能测试和原理分析几个方面进行介绍.
2 准备工作
服务器架构图如下
启动主服务器 101, 使用 info replication 命令查看状态, 可以看到 role 为 master(也就是角色为主主服务器),connected_salaves 的值为 0(从服务器数量为 0)
接下来用修改配置文件的方式将 102 机器加入的主从复制当中
然后再用命令的方式同样将 103 机器加入的主从复制当中.
2.1 用修改配置文件的方式将 102 机器加入到主从
ip 地址为 192.168.17.102 的机器的 Redis 配置文件增加 slaveof 192.168.17.101 6379
启动 102 的 redis, 状态如下
可以看到 role 变为 slave(角色为从服务器),master_host(主服务器 IP 地址)为 192.168.17.101,master_port(主服务器端口)为 6379.
此时 101 主服务器的主从状态如下, 可以看到 connected_salaves 的值变为 1, 以及增加了一行 slave0(从服务器的状态)
2.2 用命令的方式将 103 机器加入到主从
未执行 slaveof 命令的主从状态如下
开始执行 slaveof 命令
- 192.168.17.103:6379> slaveof 192.168.17.101 6379
- OK
再次查看状态, 可以看到角色已经变成从服务器
现在再来看看主服务器的状态, 可以看到从服务器数量变成 2, 又多了一条从服务器的信息
到这里主从环境就搭好了, 现在来测试一波
2.3 测试
现在主服务器 101 输入命令
- 192.168.17.101:6379> set 101 101
- OK
然后在从服务器 102 上查看所有的键, 发现有键 101, 接着设置键 102
- 192.168.17.102:6379> keys *
- 1) "101"
- 192.168.17.102:6379> get 101
- "101"
- 192.168.17.102:6379> set 102 102
- (error) READONLY You can't write against a read only slave.
发现出现错误
(error) READONLY You can't write against a read only slave.
后面在讲述出错原因
现在在从服务器 103 上查看所有的键, 发现也有
- 101
- 192.168.17.103:6379> keys *
- 1) "101"
再向主服务器 101 输入命令
- 192.168.17.101:6379> set ip ip
- OK
然后到从服务器 103 上查看所有的键
- 192.168.17.103:6379> keys *
- 1) "101"
- 2) "ip"
可以看到多了一个键, 说明主服务的数据同步到了从服务器上, 操作过程看下图
2.4 其他
2.4.1 (error) READONLY You can't write against a read only slave.
出现错误
(error) READONLY You can't write against a read only slave.
是因为
从节点默认是只读的, 如需修改可以再配置文件中修改下面这个属性
slave-read-only yes
2.4.2 主服务器设置密码
当主服务设置密码时, 配置文件需要增加如需参数
masterauth <master-password>
3 实现原理
当我在从服务器 103 上输入 slaveof 命令时, 出现如下日志
总的来说主从复制功能的详细步骤可以分为 7 个步骤:
设置主服务器的地址和端口
建立套接字连接
发送 PING 命令
身份验证
发送端口信息
同步
命令传播
接下来分别叙述每个步骤
3.1 设置主服务器的地址和端口
主从复制的第一步就是设置主服务器的地址和端口, 当输入 slaveof 命令或者在配置文件中配置信息时, 从服务器会将主服务器的 ip 地址和端口号保存到服务器状态的属性里面.
3.2 建立套接字连接
在 slaveof 命令执行之后, 从服务器会根据设置的 ip 和端口, 向主服务器简历 socket 连接.
3.3 发送 PING 命令
socket 连接成功后, 从服务器会发送一 PING 命令给主服务器.
这时候 PING 命令可以检查 socket 的读写状态是否正常, 还可以检查主服务器能否正常处理命令请求.
从服务器在发送 PING 命令时可能遇上的情况如下图
3.4 身份验证
从服务器收到主服务器的 PONG 回复后, 会检查从服务器是否设置 masterauth, 设置则进行身份验证, 未设置则跳过该步骤. 从服务器在身份验证时可能遇上的情况如下
3.5 发送端口信息
身份验证通过后, 从服务器会向主服务器发送自己的监听端口号. 主服务器收到之后会将端口号记录到从服务器对应的状态属性中. 在主服务器调用 info replication 可以看到从服务器的 port, 如下
3.6 同步
发送端口信息之后, 从服务器会向主服务器发送 PSYNC 命令, 执行同步操作, 并将自己的数据库同步至主服务器数据库当前的状态.
同步这块内容会在后面详细描述
3.7 命令传播
当完成同步操作之后, 主从服务器便会进入命令传播阶段. 这时候主从服务器的数据是一致的, 当主服务器有新的写命令时, 会将改命令发送给从服务器, 从服务器接收命令并执行便可以保证与主服务器的数据保持一致.
那么 Redis 是如何保证主从服务器一致处于连接状态以及命令是否丢失?
答: 命令传播阶段, 从服务器会利用心跳检测机制定时的向主服务发送消息.
从服务器发送的命令如下
REPLCONF ACK <replication_offset>
replication_offset 表示从服务器当前的复制偏移量
接下来看看心跳机制
3.7.1 心跳检测机制
心跳检测机制的作用有三个:
检查主从服务器的网络连接状态
辅助实现 min-slaves 选项
检测命令丢失
3.7.1.1 检查主从服务器的网络连接状态
主服务器信息中可以看到所属的从服务器的连接信息, state 表示从服务器状态, offset 表示复制偏移量, lag 表示延迟值(几秒之前有过心跳检测机制)
3.7.1.2 辅助实现 min-slaves 选项
Redis.conf 配置文件中有下方两个参数
- # 未达到下面两个条件时, 写操作就不会被执行
- # 最少包含的从服务器
- # min-slaves-to-write 3
- # 延迟值
- # min-slaves-max-lag 10
如果将两个参数的注释取消, 那么如果从服务器的数量少于 3 个, 或者三个从服务器的延迟 (lag) 大于等于 10 秒时, 主服务器都会拒绝执行写命令.
3.7.1.3 检测命令丢失
在从服务器的连接信息中可以看到复制偏移量, 如果此时主服务器的复制偏移量与从服务器的复制偏移量不一致时, 主服务器会补发缺失的数据.
4 同步原理
同步分为全量重同步和部分重同步. 那么是什么决定采取全量重同步还是部分重同步操作?
4.1 全量重同步
全量重同步的步骤如下
主节点收到从服务器的全量重同步请求时, 主服务器便开始执行 bgsave 命令, 同时用一个缓冲区记录从现在开始执行的所有写命令.
当主服务器的 bgsave 命令执行完毕后, 会将生成的 RDB 文件发送给从服务器. 从服务器接收到 RDB 文件时, 会将数据文件保存到硬盘, 然后加载到内存中.
主服务器将缓冲区所有缓存的命令发送到从服务器, 从服务器接收并执行这些命令, 将从服务器同步至主服务器相同的状态.
4.2 部分重同步
要想了解部分重同步的步骤, 需要先了解部分重同步所需要的几个属性
复制偏移量
复制缓冲区
运行 ID
4.2.1 复制偏移量
从主服务器的复制信息可以看到从服务器 slave0 和 slave1 都有一个参数 offset, 这个参数就是从服务器的复制偏移量. master_repl_offset 这个参数就是主服务器的偏移量. 如下图
主服务器的复制偏移量保存向从服务器发送过的字节数据.
从服务器的复制偏移量保存着从主服务器接收的字节数据.
通过对比主服务器和从服务器的复制偏移量就可以知道命令是否丢失, 丢失则补发复制偏移量相差的字节命令.
那么这些字节数据是存放在哪里的呢?
4.2.2 复制缓冲区
这些字节数据都是存放在主服务器的复制缓冲区里的. 复制缓冲区是一个固定长度 (fixed-size) 先进先出 (FIFO) 的队列, 默认大小为 1MB. 默认大小可以对下方的参数进行修改
# repl-backlog-size 1mb
那么复制缓冲区的数据是什么时候加入进去的呢?
答: 在命令传播阶段, 主节点除了将写命令发送给从节点, 还会发送一份给复制积压缓冲区.
复制缓冲区里面会保存着一部分最传播的写命令和每个字节相应的复制偏移量.
由于复制缓冲区的大小是有限制的, 所以保存的数据也是有限制的. 如果从服务器与主服务器的复制偏移量相差的数据大于复制缓冲去存储的数据时, 同样不会执行部分重同步.
举个例子, 主服务器的复制偏移量为 20000, 缓冲区能保存的数据只有 5000, 从服务器的复制偏移量为 10000. 这时从服务器与主服务器复制偏移量 10000, 而缓冲区只有 5000, 那么还是会执行全量重同步. 如果相差的复制偏移量小于 5000, 才会执行部分重同步.
4.2.3 运行 ID
每个 Redis 服务器启动时, 都会有自动生成自己的运行 ID.
当从服务器对主服务器进行初次复制时, 主服务器会发送自己的运行 ID 给从服务器.
当从服务器断线重连时, 会将之前主服务器的运行 ID 发送给当前连接的主服务器. 这时候会出现下面两种情况
运行 ID 和主服务器一致, 主服务器可以尝试执行部分重同步操作.
运行 ID 和主服务器不一致, 说明之前连接的主服务器与这次连接不同, 开始执行全量重同步操作.
5 相关配置
- ################################# REPLICATION #################################
- # slaveof <主服务器 ip> <主服务器端口>
- # slaveof <masterip> <masterport>
- # masterauth <主服务器 Redis 密码>
- # masterauth <master-password>
- # 当 slave 丢失 master 或者同步正在进行时, 如果发生对 slave 的服务请求
- # yes 则 slave 依然正常提供服务
- # no 则 slave 返回 client 错误:"SYNC with master in progress"
- slave-serve-stale-data yes
- # 指定 slave 是否只读
- slave-read-only yes
- # 无硬盘复制功能
- repl-diskless-sync no
- # 无硬盘复制功能间隔时间
- repl-diskless-sync-delay 5
- # 从服务器发送 PING 命令给主服务器的周期
- # repl-ping-slave-period 10
- # 超时时间
- # repl-timeout 60
- # 是否禁用 socket 的 NO_DELAY 选项
- repl-disable-tcp-nodelay no
- # 设置主从复制容量大小, 这个 backlog 是一个用来在 slaves 被断开连接时存放 slave 数据的 buffer
- # repl-backlog-size 1mb
- # master 不再连接 slave 时 backlog 的存活时间.
- # repl-backlog-ttl 3600
- # slave 的优先级
- slave-priority 100
- # 未达到下面两个条件时, 写操作就不会被执行
- # 最少包含的从服务器
- # min-slaves-to-write 3
- # 延迟值
- # min-slaves-max-lag 10
结语
主从的配置文件:[ https://github.com/rainbowda/learnWay/tree/master/learnRedis/replication , 有需要可以下载.
Redis 的主从复制功能就介绍到这里了. 虽然说主从解决了读写分离, 读数据的负载均衡, 但是一旦某个节点出现故障, 不能自动回复, 主从切换等功能. 所以就有了哨兵的功能.
来源: https://yq.aliyun.com/articles/624146