redis--04主从集群

主从集群

主从集群搭建

redis的主从集群是一个“一主多从”的读写分离集群。集群中的master节点负责处理客户端的读写请求,而slave节点仅能处理客户端的读请求。在数据库集群中,写的操作压力一般较小,压力大多来自读操作请求。

伪集群搭建与配置

在采用单线程IO模型时,为了提高处理器的利用率,一般会在一个主机中安装多台redis,构建一个redis主从伪集群。
下面是搭建一主二从伪集群

  1. 复制redis.conf
    1. 将伪集群公有的配置放到同一个配置文件,然后再分别为各个redis服务器进行个性化的配置
  2. 对共有配置进行修改
    1. 若设置了requirepass,为了能够在主机宕机时能够连接上其他副本服务器,那么也要为masterauth设置相同的值
    2. 将repl-disable-tcp-nodelay属性设置为no,以实现大的tcp包传输,减少网络开销(该操作会使得数据积累到一定量后才进行传输,若系统的流量很大,或者是副本服务器跳数很多则置为yes)
  3. 定义个性化配置
    1. 在redis.conf同目录下创建3个配置文件来对应1台主服务器2台从服务器

redis6380.conf

# 导入公共配置
include redis.conf
# 指定pidfile
# 当启动redis服务器时,会生成一个唯一的进程id,并会将该pid写入到指定文件中
pidfile /var/run/redis_6380.pid
post 6380
# 配置rdb持久化文件名
dbfilename dump6380.rdb
# 配置aof持久化文件名
appendfilename appendonly6380.aof
# 配置该服务器竞争主服务器优先级,数字越小越高
replica-priority 90

redis6381.conf

# 导入公共配置
include redis.conf
# 指定pidfile
# 当启动redis服务器时,会生成一个唯一的进程id,并会将该pid写入到指定文件中
pidfile /var/run/redis_6381.pid
post 6380
# 配置rdb持久化文件名
dbfilename dump6381.rdb
# 配置aof持久化文件名
appendfilename appendonly6381.aof
# 配置该服务器竞争主服务器优先级,数字越小越高
replica-priority 80

redis6382.conf

# 导入公共配置
include redis.conf
# 指定pidfile
# 当启动redis服务器时,会生成一个唯一的进程id,并会将该pid写入到指定文件中
pidfile /var/run/redis_6381.pid
post 6380
# 配置rdb持久化文件名
dbfilename dump6381.rdb
# 配置aof持久化文件名
appendfilename appendonly6381.aof
# 配置该服务器竞争主服务器优先级,数字越小越高
replica-priority 70
  1. 设置主从关系
    1. 分别启动三台redis服务器,注意启动时指定的配置文件以及端口号
    2. 在从服务器执行slaveof ip 端口号来指定主服务器

分级管理

若redis主从集群中的slave较多时,它们的数据同步过程会对master形成较大的性能压力。此时可以对这些slave进行分级管理。

我们只需要让低级别的slave指定其slaveof的主机为上一级slave即可,以形成一个树状结构。

容灾冷处理

在Master/Slave的Redis集群中,若Master出现宕机有两种处理方式,一组是通过手工角色调整,使Slave晋升为Master的冷处理;另一种是使用哨兵模式,实现Redis集群的高可用HA即热处理。
无论master是否宕机,slave都可以通过slaveof no one 将自己由slave晋升为master。如果其原本就有下一级的slave,那么,其就直接变成这些slave的真正master。而原来的master也会失去这个原来的slave

主从复制原理

主从复制过程

  1. 保存master地址
    1. 当slave接收到slaveof指令后,slave会立即将新的master的地址保存下来
  2. 建立连接
    1. slave中维护着一个定时任务,该定时任务会尝试着与该master建立socket连接。
    2. 如果连接成功slave会发送ping命令进行首次通信
    3. 如果连接失败则会重新发送连接请求
    4. 如果此时接收到slaveof no one命令则会停止建立链接(自己成为master)
  3. 身份认证
    1. master在接收到slave的ping命令后对slave进行身份验证
    2. 若通过master向slave发送连接成功响应
    3. 若未通过则发送拒绝连接
  4. 请求同步数据
    1. slave向master发送全量数据同步请求
  5. 数据持久化
    1. master在接收到数据同步请求后fork出一个子进程进行数据持久化
  6. 发送同步数据
    1. 当数据持久化完毕后master再fork出一个子进程将master的持久化文件发送给slave
  7. 接收并写入同步数据
    1. slave接收到master的数据并写入到本地吃鸡化文件
    2. 若此时master主进程又发生了写操作则master会将数据写入到本地内存的同时还会将其写入到同步缓存
      1. 若此时同步数据已经发送完毕则master将同步缓存中的数据发送给slave
  8. 恢复内存数据
    1. 数据同步完毕后slave读取本地持久化文件,恢复内存数据,对外服务
  9. 增量接收同步数据
    1. 对外服务中master持续接收到写操作,会以增量的方式发送给slave

数据同步演变过程

sync同步

redis2.8以前,首次通信成功后,slave会向master发送sync数据同步请求。然后master就会将其所有数据全部发送给slave,由slave保存到其本地的持久化文件中。这个过程称为全量复制
但这里存在一个问题:在全量复制的过程中可能会出现由于网络抖动而导致复制过程中断。当网络恢复后,slave与master重新连接成功,此时slave会重新发送sync请求,然后会从开头开始全量复制。
由于全量复制非常耗时,所以期间出现网络抖动的概率很高。而中断后的从头开始不仅需要小号大量的系统资源、网络带宽,而且可能会出现长时间无法完成全量复制的情况。

psync同步

redis2.8以后全量复制采用了psync同步策略。当全量复制过程出现由于网络抖动而导致复制过程中断时,当重新连接成功之后,复制过程可以“断点续传”

为实现断点续传,系统做出了三大变化

  • 复制偏移量
    • 系统为每个要传送数据进行编号,该编号从0开始,每个字节一个编号。该编号称为复制偏移量。参与复制的主从节点都会维护该复制偏移量。
  • 主节点复制ID
    • 当master启动后会动态生成一个长度为40位的16进制字符串作为当前master的复制id,该id是在进行数据同步时slave识别master使用的。通过info replication的master_replid属性可查看该id
  • 复制积压缓冲区
    • 当master有连接的slave时,在master中就会创建并维护一个队列backlog,默认大小为1MB,该队列称为复制积压缓冲区。master接收到了写操作数据不仅会写入到master主存,写入到master中为每个slave配置的发送缓存,而且还会写入到复制积压缓冲区。其作用就是用于保存最近操作的数据,以备“断点续传”时做数据补偿,防止数据丢失

psync同步过程

  1. slave向master首次提交psync同步命令PSYNC ? -1(这里的?表示动态id未知)
    1. 若当前master不支持PSYNC则master向slave进行ERR响应,告知将进行全量复制
    2. master向slave发送全量数据,开启全量复制
    3. 结束
  2. master向slave进行响应FULLRESYNC <master_replid> <repl_offset>,告知其可以进行全量复制
  3. master向slave发送全量数据,开启全量复制
    1. 若全量复制中slave与master中断且重连成功
    2. slave向master再次提交psync同步命令PSYNC <master_replid><repl_offset>
    3. master向slave进行响应,告知其可以“断点续传”CONTINUE
    4. master从<repl_offset + 1>开始向slave进行“断点续传”

psync存在问题

在psync数据同步过程中,若slave重启,在slave内存中保存的master的动态id与续传offset都会消失,“断点续传”将无法进行,从而只能进行全量复制,导致资源浪费

psync同步改进

redis4.0对psync进行了改进,提出了“同源增量同步”策略

  • 解决slave重启问题
    • 直接将master的动态id写到slave的持久化文件中,使得重启后仍然能从持久化文件中得到master的动态id
  • 解决slave易主问题
    • 由于改进后的psync中每个slave都在本地保存了当前master的动态id,故当slave晋升成新的master后,其本地仍然存在之前master的动态id

redis6.0对同步过程提出了“无盘全量同步”与“无盘加载”,避免了耗时的io操作

  • 无盘全量同步
    • master的主进程fork出的子进程直接将内存中的数据发送给slave,无需经过磁盘
  • 无盘加载
    • slave在接收到master发来的数据后不需要将其写入到磁盘文件,而是直接写入到内存,这样slave就可以快速完成数据恢复

redis7.0对复制积压缓冲区进行了改进,让各个slave的发送缓冲区共享复制积压缓冲区。这使得复制积压缓冲区的作用,除了可以保障数据的安全性外,还作为所有slave的发送缓冲区,充分利用了复制积压缓冲区

哨兵机制实现

简介

对于Master宕机后的冷处理方案无法实现高可用性(需要手动指定master)。在redis2.6版本开始提供了高可用的解决方案:哨兵机制。在集群中再引入一个节点,该节点充当Sentinel哨兵,用于监视Master的运行状态,并在Master宕机后自动指定一个Slave作为新的Master。
对于单哨兵也存在宕机可能,故还要为哨兵也创建一个集群。
哨兵在监视master状态时,会定时向master发送心跳。当哨兵集群中有一定数量的哨兵没有接收到响应就说明master已经宕机。此时会有一个sentinel来做failover故障转移,将原理的某一个Slave晋升为master

搭建redis高可用集群

下面是搭建一主二从三哨兵伪集群,一主二从使用上小节搭建即可

搭建思路与主从服务器类似

  1. 复制sentinel.conf
  2. 修改sentinel.conf得到公共哨兵配置
    1. 注释掉sentinel monitor mymaster 127.0.0.1 6379 2
      1. 该行配置用于指定监听的master的ip,端口号以及确定master宕机的最少哨兵数
      2. 由于选举新master仍然需要大多数哨兵支持,故该选项值应该大于哨兵个数的一半,以防止出现主观确认master宕机,但是不能选举出新master的情况
    2. sentinel auth-pass项处设置master的密码
      1. 所有的slave和master如果有密码必须相同
      2. 有密码和无密码可以混合使用
  3. 编写个性化哨兵配置
# sentienl26380.conf

# 包含公共配置文件
include sentinel.conf
# 指定动态id存放文件
pidfile /var/run/sentinel_26380.pid
# 指定端口号
port 26380
# 指定主机ip、端口号、主观master宕机最少票数
sentinel monitor mymaster 192.168.92.1 6380 2
# sentienl26381.conf

# 包含公共配置文件
include sentinel.conf
# 指定动态id存放文件
pidfile /var/run/sentinel_26381.pid
# 指定端口号
port 26381
# 指定主机ip、端口号、主观master宕机最少票数
sentinel monitor mymaster 192.168.92.1 6380 2
# sentienl26382.conf

# 包含公共配置文件
include sentinel.conf
# 指定动态id存放文件
pidfile /var/run/sentinel_26382.pid
# 指定端口号
port 26382
# 指定主机ip、端口号、主观master宕机最少票数
sentinel monitor mymaster 192.168.92.1 6380 2
  1. 启动master和slave,并用slaveof命令来为slave指定master(这里master是192.168.92.1 6380)
  2. 启动所有sentinelredis-sentinel 配置文件名

sentinel优化配置

  • sentinel down-after-milliseconds
    • 指定master,slave,sentinel未返回心跳响应的最小毫秒数
    • 对于哨兵sentinel,它不只是给master发送心跳,它还和能连接上的所有服务器发送心跳
  • sentinel parallel-syncs
    • 设置同时进行同步的slave个数
    • 进行同步的slave对外不能提供读写服务
    • 这表明着redis在同步时可以牺牲一致性来保证可用性
  • sentinel failover-timeout
    • 故障转移的超时时间
    • 若超时则以两倍该时间为新master的故障转移超时时间
    • 其余slave从旧的已宕机的master转移到新master的超时时间
    • 哨兵集群取消对slave晋升为master的后悔时间
    • 其余slave从新的master同步数据所花费的最大时间,倘若超过了这个时间还未完成同步,则会以更大的同时进行同步slave个数进行同步
  • sentinel deny-scripts-reconfig
    • 不能自动修改配置文件以保证程序继续进行

哨兵机制原理

三个定时任务

sentinel维护着三个定时任务以监测redis节点及其它sentinel节点状态

  • info任务
    • 每个sentinel节点以10秒每次的频率向redis集群中的每个节点发送info命令,以获取最新的redis拓扑结构
  • 心跳任务
    • 每个sentinel节点每秒都会向所有redis节点及其他sentinel节点发送一条ping命令,以检测这些节点的存活状态。该任务是判断节点在线状态的重要依据
  • 发布/订阅任务
    • 每个sentinel节点在启动时都会向所有redis节点订阅__sentinel__:hello主题的信息,当redis节点中该主题的信息发生了编号,就会立即通知到所有订阅者。
    • 启动后,每个sentinel节点以每两秒一次的频率向每个redis节点发布一条__sentinel__:hello主题的信息,该信息是当前sentinel对每个redis节点在线状态的判断结果及当前sentinel节点信息
    • 当sentinel节点接收到__sentinel__:hello主题信息后,就会读取并解析这些信息,然后主题完成以下三项工作
      • 如果发现有新的sentinel节点加入,则记录下新加入sentinel节点信息,并与其建立连接
      • 如果发现有sentinel leader选举的选票信息,则执行leader选举过程
      • 汇总其他sentinel节点对当前redis节点在线状态的判断结果,作为redis节点客观下线的判断依据

redis节点下线判断

  • 主观下线
    • 每个sentinel节点每秒会向每个redis节点发送ping心跳检测,如果sentinel在down-after-milliseconds时间内没有接收到某redis节点的回复,则sentinel节点就会对该redis节点做出“下线状态”的判断。这个判断仅仅是当前sentinel节点的意见。
  • 客观下线
    • 当sentinel主管下线的节点是master是,该sentinel系欸但会向每个其他sentinel节点发送sentinel is-master-down-by-addr命令,以询问其对master在线状态的判断结果。这些sentinel节点在接收到命令后回想这个发问sentinel节点响应0(在线)或1(下线)。当sentinel收到超过quorum个下线判断后,就会对master做出客观下线判断

sentinel leader选举

  • 当sentinel节点对master做出客观下线判断后会由sentinel leader来完成后续的故障转移。
  • sentinel集群的leader选举是通过raft算法实现的(该算法后面会详细说)
  • 在网络没有问题的前提下,基本上谁做出了客观下线的判断,谁就会首先发起sentinel leader的选举,谁就会当选leader
  • sentinel leader选举会在故障转移发生之前进行,故障转移后leader关系会被取消

master选择算法

在进行故障转移时,sentinel leader需要从所有redis的slave节点中选择处新的master

选择master的算法为

  • 过滤所有主观下线,或心跳没有响应sentinel或replica-priority值为0的redis节点
  • 在剩余redis节点中选择处replica-priority(优先级数)最小的节点列表。若只有一个节点则直接返回
  • 从优先级相同的节点列表中选择复制偏移量最大(同步次数最多)的节点。若只有一个节点则返回
  • 从复制偏移量相同的节点列表中选择动态id最小的节点返回

故障转移的过程

  1. sentinel leader根据master选择算法选出一个slave节点作为新的master
  2. sentinel leader向新maser节点发送slaveof no one指令,使其晋升为master
  3. sentinel leader向新master发送info replication指令,获取master动态id
  4. sentinel leader向其余redis节点发送消息,告知它们新master的动态id
  5. sentinel leader向其余redis节点发送slaveof <mastip> <masterPort>指令,使它们成为新master的slave
  6. sentinel leader从所有slave节点中每次选择处parallel-syncs个slave从新master同步数据,直至所有slave全部同步完毕
  7. 故障转移完毕

节点上线方法

  • 原redis节点上线
    • 直接启动即可
  • 新redis节点上线
    • 启动服务器
    • 使用slaveof命令加入集群
  • sentinel节点上线
    • 需要在配置文件中修改sentinel monitor属性,指定监控的master
    • (如果是之前存在的sentinel节点也需要指定,因为master可能改变过)
    • 启动哨兵

CAP定理

概念

  • C(一致性)
    • 分布式系统中多个主机之间是否能够保持数据一致的特性。即当系统数据发生更新操作后,各个主机中的数据仍然处于一致的状态
  • A(可用性)
    • 系统提供的服务必须一直处于可用的状态,即对于用户的每一个请求,系统总是可以在有限的时间内对用户做出响应
  • P(分区容错性)
    • 分布式系统在遇到任何网络分区故障时,仍然能够保证对外提供满足一致性和可用性的服务

定理

CAP定理的内容是:对于分布式系统,网络环境相对是不可控的,出现网络分区是不可避免的,因此系统必须具备分区容错性。但系统不能同时保证一致性与可用性,即要么CP要么AP

BASE理论

BASE是基本可用、软状态、最终一致性的简写。其核心思想是:即使无法做到强一致性,但每个系统哦都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性

  • 基本可用
    • 指分布式系统在出现不可预知故障的时候,允许损失部分可用性
  • 软状态
    • 指允许系统数据存在的中间状态,并认为该中间状态的存在不会影响系统整体可用性,即允许系统主机键进行数据同步的过程存在一定延时。软状态,其实就是一种灰度状态,过渡状态
  • 最终一致性
    • 指经过一段时间的同步后,最终能够达到一致性。不需要实时一致性

Raft算法

概念

Raft算法是一种通过对日志复制管理来达到集群节点一致性的算法。这个日志复制管理发生在集群节点中的leader与followers之间。raft通过选举处的leader节点负责管理日志复制过程,以实现各个节点间数据的一致性

  • leader
    • 唯一负责处理客户端写请求的节点;也可以处理客户端读请求;同时负责日志复制工作
  • candidate
    • leader选举的候选人,其可能会成为leader,是一个选举中的过程角色
  • follower
    • 可以处理客户端读请求;负责同步来自于leader的日志;当接收到其它cadidate的投票请求后可以进行投票;当发现leader挂了,其会转变为candidate发起leader选举

leader选举

  • leader的选择的目的是要选出有大的term值和日志信息的节点

  • 当一个节点给另一个节点投票过后,投票的节点会将当前投票请求继续传递给邻接节点

  • 参与选举

    1. 当follower在心跳超时范围内没有接收到来自leader的心跳,则认为leader宕机。此时会使得本地term加1
    2. 若此时接收到了其它candidate的投票请求,则会将选票投给这个candidate
    3. 若没有接收到投票请求则自己从follower变为candidate
      1. 若之前尚未投票,则向自己投票
      2. 向其它节点发出投票请求,然后等待响应
  • 参与投票

    1. follower在接收到投票请求后进行投票判断(以下是满足条件后投给请求方)
    2. 若发出投票请求的candidate的term大于等于自己的term
    3. 若在自己当前term内,选票还未投递
    4. 接收到多个candidate,采用first-come-first-served方式投票
  • 等待响应

    • 当一个candidate发出投票请求后会等待其它节点的响应结果。
    • 收到过半选票
      • 成为新的leader
      • 将该消息广播给所有节点
    • 接收到其它candidate发送的leader通知
      • 比较新leader的term大于等于自己的term,则自己转换为follower
    • 选票未过半,同时无新leader通知
      • 重新发起选举
  • 选举时间

    • 在大多数情况下,当leader宕机后,follower几乎是同时感知到。为了避免较多candidate票数相同的情况,Raft算法采用了随机选举超时策略。
    • 其会为follower随机分配一个选举发起时间(150~300ms)只有达到了这个时间的follower才能转变为candidate。

数据同步

在leader选举出来的情况下,leader通过日志复制管理实现集群中各节点数据的同步

  • 状态机
    • 不同server中的状态机若当前状态相同,然后接受了相同输入,则一定会得到相同输出
  • 处理流程
    • leader在接收到client的写操作请求后,会将数据与自己的term封装为一个box,并随着下一次心跳发送给所有followers,以获得大家对该box的意见。同时在本地将数据封装为日志
    • follower在接收到来自leader的box后首先会比较该box的term与本地term,只要不必自己的term小就接受该box,并向leader回复同意。同时会将该box中的数据封装为日志。
    • 当leader接收到过半同意响应后,会将日志commit到自己的状态机,状态机会输出一个结果,同时日志状态会变为committed
    • 同时leader还会通知所有follower将日志commit到它们本地的状态机,日志状态变为committed
    • 在commit通知发出的同时,leader也会向client发出成功处理的响应
  • AP支持
    • log由term index、log index 、command构成。为了确保可用性,各个节点中的日志可以不完全相同,但leader会不断给follower发送box,以使各个节点的log最终达到相同。

脑裂

raft集群存在脑裂问题,在多机房部署中,由于网络连接问题,很容易形成多个分区,从而容易产生脑裂,导致数据不一致。
要注意脑裂不是leader宕机,是网络问题引起的集群间通信故障

以下讨论的是各个机房服务器数量相近的情况(避免出现少数机房决定多数机房情况)
这里的邻接,可达等是图论术语

  • leader对所有节点可达
    • leader与所有其他机房邻接
      • 成功容灾,leader不变
    • leader不能与所有其它机房邻接
      • 成功容灾,重新选举leader
  • leader存在不可达节点
    • 不可达机房节点度大于0
      • 发生脑裂,新网络分区选举出新leader;
      • 旧leader所在分区继续按该结论分析
    • 不可达机房节点度等于0
      • 发生脑裂,度为0的机房节点自身成为单独集群
      • 旧leader所在图继续按照该结论分析

leader宕机处理

  • 写请求到达前leader宕机
    • 由于请求还未到达集群,故该请求会被集群忽视,对集群数据一致性影响
    • 集群内部会选举产生新leader
    • 由于stale leader 未发送成功处理响应,client会重新发送写请求
  • 未开始发送同步数据前leader宕机
    • 集群内部选举产生新leader
    • stale leader重启完成后会作为follower重新加入集群,并同步新leader数据。之前接收到的client写请求数据被丢弃
    • 由于stale leader 未发送成功处理响应,client会重新发送写请求
  • 同步数据过程中leader宕机
    • 集群内部选举产生新leader
    • 若leader产生于已完成数据接收的follower,其会继续将前面接收到的写操作请求转换为日志,并写入到本地状态机,并向所有follower发出询问。在获取过半同意响应后会向所有followers发送commit指令,同时向client进行响应
    • 若leader产生于尚未完成数据接收的follower那么原来已完成接收的follower则会放弃曾经接收到的数据,由于client没有接收到响应,故会重新发送写请求
  • commit通知发送后leader宕机
    • 由于stale leader已向client发送成功接收响应,且commit通知已经发出,说明该写操作请求已经被server成功处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值