【Redis】Redis 主从复制

一、主从复制概念

互联网"三高"架构:高并发、高性能、高可用

高可用就是5个9

为了避免单点redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服务器上,连接在一起,并保证数据是同步的,即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据冗余备份

多台服务器连接方案

  • master:主服务器,主节点,主库,提供数据,一般负责客户端的写数据操作(客户端的写操作少)
  • slave:从服务器,从节点,从库,接受数据,定期同步master中的数据,负责客户端的读数据操作(客户端的读操作多)
  • 主从复制特征:一个master可以拥有多个slave,一个slave只对应一个master

二、高可用的集群方案

假如此时一台slave故障,其他的slave可以对外提供读数据服务,当故障的slave恢复后,也可以从master进行数据恢复

假如此时master故障,我们会选择一台slave作为新的master对外提供写数据服务,以及和slave进行主从复制

此外,为了防止master宕机引发问题,我们还可以使用master集群

当master压力很大时,我们可以使用多级master用于分担压力(这会导致一些问题,需要使用哨兵解决)

主从复制作用

  • 读写分离:master写、slave读,提高服务器的读写负载能力
  • 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
  • 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
  • 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
  • 高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案

三、主从复制工作流程概述

主从复制过程大体可以分为3个阶段:建立连接阶段(即准备阶段),数据同步阶段(初始化slave的数据),命令传播阶段(slave执行和master相同的写操作)

四、阶段一:建立连接阶段

建立slave到master的连接,使master能够识别slave,master保存slave的port,slave保存master的ip:port

方式一:客户端发送命令(客户端连接服务器后,操作一台服务器成为另一台服务器的slave)

xml 复制代码
slaveof <masterip><masterport>

方式二:启动服务器参数(不用客户端连接服务器,服务器启动时直接连接另一台服务器,并成为其slave)

xml 复制代码
redis-server --slaveof <masterip><masterport>

方式三:服务器配置

xml 复制代码
slaveof <masterip><masterport>

1. 用客户端操作,实现主从复制(命令方式)

修改使用6379端口和6380端口启动的配置文件,设置为前台启动,不使用日志文件,日志打印到前台

在6379和6380端口启动redis服务

登录6380的redis服务器,使用slaveof使6380成为6379的slave

6380这边多了一些日志信息,说明连接6379成功,且成为了6379的slave

6379这边也多了一些日志信息,表示建立连接成功且数据同步成功了

使用客户端连接作为master的6379服务器,进行写操作

在连接到6380客户端这边获取key,虽然是在6379服务器写的数据,由于进行了主从复制,6380这边依然可以获取

2. 服务器启动时,直接另一台服务器的成为slave,实现主从复制(命令方式)

6380成功成为6379的slave

3. 配置文件方式实现主从复制

上述两种使用命令的方式,实现主从复制都不是主流,最多的还是使用配置文件

修改配置文件

使用修改后的配置文件启动redis服务

连接成功

6379进行写操作

由于配置了主从复制,6380同步了6379的数据,成功获取key

输入info,查看msater相关信息

输入info,查看slave相关信息

4. 断开主从复制

perl 复制代码
slaveof no one  # slave客户端发送,与master断开连接

slave客户端发送命令

master客户端修改name

slave并没有进行同步,说明很主从复制已经断开了

5. 设置权限校验

  • master客户端发送命令设置密码(一旦设置了密码,客户端访问就必须带上密码)
arduino 复制代码
config set requirepass <password>
  • master配置文件设置密码
arduino 复制代码
config set requirepass <password>
config get requirepass
  • slave客户端发送命令设置密码
xml 复制代码
auth <password>
  • slave配置文件设置密码
xml 复制代码
masterauth <password>
  • slave启动服务器设置密码
css 复制代码
redis-server --a <password>

五、阶段二:数据同步阶段

在slave初次连接master后,同步master中的所有数据到slave,将slave的数据库状态更新成master当前数据库状态

全量复制: 用RDB的方式同步master中的大量数据,slave拿到的是数据 ,恢复速度快
部分复制: master执行bgsave生成RDB文件过程中收到的客户端的指令会保存在一个缓冲区,用AOF的方式记录并发送给slave,slave收到AOF文件后会进行bgrewriteaof,然后再执行AOF文件中的指令

同步完成的最终状态: slave具有master端全部数据,包含RDB过程接收的数据;而master则保存slave当前数据同步的位置

数据同步阶段master说明

  1. 如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行
  2. 复制缓冲区大小设定不合理,会导致数据溢出。如果进行全量复制周期太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态
  1. master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执行bgsave命令和创建复制缓冲区
arduino 复制代码
repl-backlog-size 1mb  # 修改复制缓冲区大小

数据同步阶段slave说明

  1. 为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭数据同步阶段的对外服务
bash 复制代码
slave-serve-stale-data yes|no
  1. 数据同步阶段,master发送给slave信息可以理解master是slave的一个客户端,主动向slave发送命令
  2. 多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,如果master带宽不足,因此数据同步需要根据业务需求,适量错峰
  3. slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,中间的节点既是master,也是slave。注意使用树状结构时,由于层级深度,导致深度越高的slave与最顶层master间数据同步延迟较大,数据一致性变差,应谨慎选择

六、阶段三:命令传播阶段

当master数据库状态被修改后,导致主从服务器数据库状态不一致,此时需要让主从数据同步到一致的状态,同步的动作成为命令传播

master将收到的写命令发送给slave,slave收到后执行命令

命令传播阶段如果出现了断网的现象,短时间网络中断需要进行部分复制,长时间网络中断则进行全量复制

部分复制的三个要素:服务器的运行id (run_id)、主服务器的复制积压缓冲区、主从服务器的复制偏移量

1. 服务器的运行id (run_id)

  • 概念: 服务器运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id
  • 组成: 运行id由40位字符组成,是一个随机的十六进制字符,例如:fdc9ff13b9bbaab28db42b3d50f852bb5e3fcdce
  • 作用: 运行id被用于在服务器间进行传输,识别身份,如果想两次操作均对同一台服务器进行,必须每次操作都携带对应的运行id,用于对方识别
  • 实现方式: run_id在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发送给slave,slave保存此ID,通过info Server命令,可以查看节点的run_id

2. 主服务器的复制积压缓冲区

为了解决由于突发原因(网络不通等...),只有部分slave同步了master的数据的问题,redis需要使用一个复制积压缓冲区

  • 复制积压缓冲区: 是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区。默认存储空间大小是1M(可配置),由于存储空间大小是固定的,当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列
  • 由来: 每台服务器启动时,如果开启有AOF或被链接成为master节点,即创建复制缓冲区
  • 作用: 用来保存master收到的所有指令(仅影响数据变更的指令,例如set、select)
  • 数据来源: 当master接收到主客户端的指令时,除了将指令执行,会将该指令存储到缓冲区中

复制积压缓冲区工作原理

一条指令会被解析成AOF格式,然后存入复制积压缓冲区

master记录给不同slave发送的信息对应的offset,slave记录已接收的信息对应的offset,通过offset区分不同的slave当前数据传播的差异

3. 主从服务器的复制偏移量offset

  • 概念: 一个数字,描述复制缓冲区中的位置
  • 作用: 同步信息,对比master与slave的差异,当slave断线后,恢复数据使用

master需要记录给多个slave发送数据对应的位置(多个),发送一次记录一次;slave需要记录master发送过来的数据对应的位置(一个),接收一次记录一次

七、数据同步和命令传播阶段工作流程

八、心跳机制

进入命令传播阶段后,master与slave间需要进行数据同步,使用心跳机制进行通信,同时保持双方连接在线

master心跳: 只是ping一下slave,判断slave是否在线,周期由repl-ping-slave-period决定,默认10秒。可通过INFO replication获取slave最后一次连接时间间隔,lag项维持在0或1视为正常,否则心跳异常

slave心跳: slave 每秒发送一次REPLCONF ACK {offset}汇报slave自己的复制offset,获取最新的数据变更指令,同时判断master是否在线

当很多的slave离线或延迟过高时,master为保障数据稳定性,将拒绝所有数据同步操作;slave数量少于2个或所有slave延迟都大于等于10s时,强制关闭master写功能,停止数据同步

python 复制代码
min-slave-to-write 2     # 设置最少的slave数量,少于这个值则强制关闭master写功能,停止数据同步
min-slave-max-lag  10    # 设置slave最大的延迟,少于这个值则强制关闭master写功能,停止数据同步

slave数量和延迟由slave发送REPLCONF ACK命令做确认

九、主从复制常见问题

1. 频繁的全量复制

2. 频繁的网络中断

3. 数据不一致

相关推荐
轻口味6 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王42 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀1 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
盛派网络小助手1 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
∝请叫*我简单先生2 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
zquwei3 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
dessler3 小时前
Docker-run命令详细讲解
linux·运维·后端·docker