搭建主从集群

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理

我们会在同一个虚拟机中利用3个Docker容器来搭建主从集群,容器信息如下:

容器名

角色

IP

映射端口

r1

master

192.168.21.129

7001

r2

slave

192.168.21.129

7002

r3

slave

192.168.21.129

7003

【Redis】-主从集群(主从同步原理、哨兵原理)_主从集群_02

version: "3.2"

services:
  r1:
    image: redis
    container_name: r1
    network_mode: "host"
    entrypoint: ["redis-server", "--port", "7001"]
  r2:
    image: redis
    container_name: r2
    network_mode: "host"
    entrypoint: ["redis-server", "--port", "7002"]
  r3:
    image: redis
    container_name: r3
    network_mode: "host"
    entrypoint: ["redis-server", "--port", "7003"]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

将其传至虚拟机的/root/redis/目录下

执行命令

docker compose up -d
  • 1.

虽然我们启动了3个Redis实例,但是它们并没有形成主从关系。我们需要通过命令来配置主从关系:

# Redis5.0以前
slaveof <masterip> <masterport>
# Redis5.0以后
replicaof <masterip> <masterport>
  • 1.
  • 2.
  • 3.
  • 4.

先建立连接

docker exec -it r1 redis-cli -p 7002
//查看信息
 info replication
 //建立关系
 slaveof 192.168.21.129 7001
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_03

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理_04

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理_05

主从同步原理

当主从第一次同步连接断开重连时,从节点都会发送psync请求,尝试数据同步:

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_06

怎么判断slave是否是第一次来

根据 replicationID来判断

 replicationID:每一个master节点都有自己的唯一id,简称replid

当没建立连接之前,每个master节点都有自己的唯一id(没建立连接之前,每一个身份都默认是master),集群连接以后,变为slave以后,所有的slave节点的id都和自己的那个主节点id一样,

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_07

全量同步实现方案

执行bgsave命令生成RDB文件,bgsave是一个后台执行的命令,当这个命令执行的时候,会开启一个独立的进程,然后回把reids在内存中的所有数据都持久化到一个硬盘中,写到RDB文件里

然后把RDB文件发给slave,slave把自己的数据清理完,然后将RDB数据全部加载进去

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_08

增量同步实现方案

master怎么知道slave与自己的数据差异在哪里呢?

此时我们就得知道offset的含义了

offset: repl_backlog中写入过的数据长度,写操作越多,offset值越大,主从的offset一致代表数据一致

这就要说到全量同步时的repl_baklog文件了。这个文件是一个固定大小的数组,只不过数组是环形,也就是说角标到达数组末尾后,会再次从0开始读写,这样数组头部的数据就会被覆盖。

repl_baklog中会记录Redis处理过的命令及offset,包括master当前的offset,和slave已经拷贝到的offset

【Redis】-主从集群(主从同步原理、哨兵原理)_主从集群_09

slave与master的offset之间的差异,就是salve需要增量拷贝的数据了。

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_10

这样就实现了增量同步

但是当slave的offset被覆盖了,就需要进行全量同步了

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理_11

优化

可以从以下几个方面来优化Redis主从就集群:

  • 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
  • Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
  • 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
  • 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力

哨兵原理

Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的具体作用如下:

  • 监控: Sentinel会不断检查您的master和slave是否按预期工作
  • 自动故障切换:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
  • 通知:当集群发生故障转移时,Sentinel会将最新节点角色信息推送给Redis的客户端

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理_12

服务状态监控

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:

  • 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线
  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理_13

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_14

选举新的master

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:

  • 首先会判断slave节点与master节点断开时间长短,如果超过指定值(down-after-milliseconds*10)则会排除该slave节点
  • 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
  • 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高(主要
  • 最后是判断slave节点的运行id大小,越小优先级越高。

如何实现故障转移

当选中了其中一个slave为新的master后(例如slave1 ),故障的转移的步骤如下:

  • sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master


  • sentinel给所有其它slave发送slaveof 192.168.150.101 7002命令,让这些slave成为新master的从节点,开始从新的master上同步数据。


  • 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理_15

搭建哨兵集群

首先,我们停掉之前的redis集群:

# 老版本DockerCompose
docker-compose down

# 新版本Docker
docker compose down
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_16

sentinel announce-ip "192.168.21.129"
sentinel monitor hmaster 192.168.150.101 7001 2
sentinel down-after-milliseconds hmaster 5000
sentinel failover-timeout hmaster 60000
  • 1.
  • 2.
  • 3.
  • 4.

说明:

  • sentinel announce-ip "192.168.21.129":声明当前sentinel的ip
  • sentinel monitor hmaster 192.168.21.129 7001 2:指定集群的主节点信息
  • hmaster:主节点名称,自定义,任意写
  • 192.168.21.129 7001:主节点的ip和端口
  • 2:认定master下线时的quorum
  • sentinel down-after-milliseconds hmaster 5000:声明master节点超时多久后被标记下线
  • sentinel failover-timeout hmaster 60000:在第一次故障转移失败后多久再次重试

我们在虚拟机的/root/redis目录下新建3个文件夹:s1s2s3,然后将sentinel.conf文件分别拷贝一份到3个文件夹中。

接着修改docker-compose.yaml文件,内容如下:

version: "3.2"

services:
  r1:
    image: redis
    container_name: r1
    network_mode: "host"
    entrypoint: ["redis-server", "--port", "7001"]
  r2:
    image: redis
    container_name: r2
    network_mode: "host"
    entrypoint: ["redis-server", "--port", "7002", "--slaveof", "192.168.21.129", "7001"]
  r3:
    image: redis
    container_name: r3
    network_mode: "host"
    entrypoint: ["redis-server", "--port", "7003", "--slaveof", "192.168.21.129", "7001"]
  s1:
    image: redis
    container_name: s1
    volumes:
      - /root/redis/s1:/etc/redis
    network_mode: "host"
    entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27001"]
  s2:
    image: redis
    container_name: s2
    volumes:
      - /root/redis/s2:/etc/redis
    network_mode: "host"
    entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27002"]
  s3:
    image: redis
    container_name: s3
    volumes:
      - /root/redis/s3:/etc/redis
    network_mode: "host"
    entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27003"]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

输入命令

docker-compose up -d
  • 1.

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_17

【Redis】-主从集群(主从同步原理、哨兵原理)_Redis_18

【Redis】-主从集群(主从同步原理、哨兵原理)_哨兵原理_19