Redis学习笔记:主从和哨兵

这是本人学习的总结,主要学习资料如下

  • B站狂神说,redis教程

1、主从复制概述

主从复制是指将一台服务器的数据复制到其它服务器。前者称为主机,后者称为从机。只能从主机写到从机,不能反过来。主机以写为主,从机以读为主。

在这里插入图片描述
因为大部分请求都是以读,所以会有这样的设计。

一般主从的最低配置是『一主二从』。其实『一主一从』也可以,但是后面会涉及到哨兵模式,至少需要两台从机。



1.2、主从复制的用途

  • 数据冗余:从机相当于主机的数据的热备份,是持久化的另一种备份方式。
  • 故障修复:当主机发生严重问题时,就能用从机恢复数据。
  • 负载均衡:主机负责写,从机负责读,可大大提高并发量。

1.3、redis主从复制的特点

  • 全量复制和增量复制同时运行:全量复制是指,当一个主机开启一段时间以后,有一个从机突然关联这个主机,那主机会将现有的所有数据都复制给从机;增量复制是指,当一个主机会将增加的数据复制给从机。
  • 主机断线后从机不丢数据:我做了实验,当主机shutdown以后,从机中的数据不会被删除,依旧可以读。
  • 主机上线进行全量复制:当主机重新上线以后,会从持久化文件中备份数据,这时候会对从机进行一次全量复制。我做了实验,主机掉线,从机可以继续读。删除主机的dump.rdb文件,重启主机,从机的数据也没了。
  • 主从复制具有传递性:从机可以为别人的主机,当该从机的主机复制数据给该从机时,该从机也会作为主机将数据复制给它的从机。尽管具有传递性,只要某个redis机子是别人的从机,那就决不允许该从机直接接受写入指令。

2、前期准备

2.1、开启多个本地redis服务模拟集群

  1. 复制两份redis.conf文件,这两份文件分别是两个从机的启动配置文件。改写这两个文件的端口号,我是改成了6380和6381。
  2. 改写配置文件的日志文件名,持久化文件名,避免三个redis服务产生的记录混杂。我将日志文件名改成『端口号.log』,持久化文件名改成『dump+端口号.rdb』。
logfile "6379.log"
dbfilename "dump6379.rdb"
  1. 现有三份redis.conf文件,redis.conf原文件我当做主机,端口6379,另外两个文件redis-slave1.confredis-slave2.conf我当从机,端口号分别是63806381
    请添加图片描述
    之后cd到redis安装目录下,使用命令redis-server /*/redis.conf指定指定配置文件开启redis服务即可。

在这里插入图片描述

  1. 配置主从关系:所有的redis服务默认都是主机,配置主从都是在从机上配置。使用指令slaveof ip port,指定本机是谁的从机,或者启动前在配置文件中修改。下面指令将slave1slave2都设为6379的从机。
MacBook-Pro:etc user$ redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
# another terminal
MacBook-Pro:etc user$ redis-cli -p 6381
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK

另外我们可以使用info replication查看主从配置信息。配置好之后,主机写的数据从机就能立刻读到,同时从机的任何写操作都是禁止的,主机可以随意读写。
这里我们在slave2中执行info replication,可以看到下面的信息。

127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:182
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:97385f0960597e07bbb059164b2ef7ebfd4aa6a0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:182
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:182

这时候我们在主机写的数据,都可以在从节点读到,这部分就不演示了。同时从节点也无法写数据。

127.0.0.1:6380> set k1 v1
(error) READONLY You can't write against a read only replica.



3、主从复制流程

  1. 输入slaveof ip port以后,该命令会保存主机信息,等待定时任务调用信息建立连接。
  2. 定时任务读取ipport,根据这些信息想主机发送socket连接;发送ping命令查看连接是否正常;之后是一些权限校验的操作。
  3. 建立连接后,主机通过RDB文件全量复制所有信息到从节点。之后不停地复制增量信息。

请添加图片描述

在2.8版本以前,第五步的psync是全量复制,但如果数据很大时,这里的速度就会变得比较慢。在2.8版本以后,psync也开始支持部分数据复制。

下面是第五步psync的具体流程。


3.1、psync

  1. 从节点发送psync ? -1,表示需要同步数据,-1表示同步全部数据。
  2. 主节点发送确认信息+FULLRESYNC同意同步,并且发送ID,和offset。
    这里的idreplication id,是这次复制的唯一标识。因为主从之间数据同步不止一次,所以会有多个replication id
    我们可以通过info replication查看id。
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=142534,lag=0
master_replid:97385f0960597e07bbb059164b2ef7ebfd4aa6a0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:142534
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:142534

  1. 之后主节点开始执行bgsave指令开始持久化数据,生成RDB文件。文件生成后发给从节点。
    和其他持久化过程一样,在生成RDB文件过程中有新数据写入时,为了防止丢失这些新数据,主节点会开辟一个缓冲区client-output-buffer。这个缓冲区会存储这些新数据,之后会继续同步给从节点保证主从一致性。
    这里是下图中低5、7步的内容。
  2. 从节点接收到RDB文件后开始清楚旧数据并加载新的RDB文件。如果主节点的缓冲区有新数据进来,新数据会在从节点加载完RDB文件后更新到从节点。

请添加图片描述


  • client-output-buffer-limit replica 89mb 64mb 60,在RDB生成和发送时,该配置会对client-out-buffer进行限制。

    • 89mb,意味着client-output-buffer的大小是89MB,如果新数据超过了这个值,那本次主从复制也失败。
    • 64mb 60,意味着如果在60s内有64mb的数据写入,那本次主从复制失败。
  • repl-timeout 60,网络超时设置。这个配置意味着,当主节点开始向从节点传输RDB文件后开始计时,如果时间超过60s则判定这次主从复制失败,从节点清除已接收的部分RDB数据。


3.2、部分复制

部分复制(partial resynchronization),这个机制是用在这个的一个情况。

全量复制中主从节点之间网络出现中断并且连接也超过repl-timeout规定的时间,等到下次网络恢复后,从节点会开始请求部分复制。

  1. 在网络断开前从节点也接收到了一些数据。这些数据的大小就是偏移量offset。从节点将offset作为参数发送psync指令,表示希望主节点从offset开始继续发送后面的数据。
  2. 主节点将偏移量靠后的数据放入repl-backlog缓存区中,成为复制积压缓冲区,将这个缓冲区塞满数据为止。
  3. 主节点发起判断,判断从节点的数据能否和repl-backlog中的数据衔接上。如果能则从repl-backlog中将对应的数据同步给从节点;如果不能证明从节点所需要的数据太多了,于是主节点放弃这次部分复制转而开启全量复制。

请添加图片描述


  • repl-backlog-size 1mb:用于控制repl-backlog缓存区的大小,默认是1mb。如果值太小,那基本上不会有部分复制,全是全量复制;如果太大那

4、哨兵模式

现在有这样一个场景,如果主机挂掉了,而且短时间内有无法恢复,那就让redis服务只有读没有写吗?听起来有些浪费资源,也不太实际。事实上,当我们发现主机挂掉以后,可以指定一个新的节点为主机,继续维持redis的服务。

找到一个从机,执行指令slaveof no one,这时候该从机就可以变成主机,可以提供写服务,同时其他从机的主从关系维持不变。

这样的解决方式也带来一个问题,如果原本的主机抢救回来了,那也是一个光杆司令。系统就会变成有两个主机,各自有自己的端口号。要想回到最初的状态又要使用指令slaveof ip port,比较麻烦。所幸的是,redis提供了哨兵模式帮助我们自动完成这些事,服务更及时,更有效。



4.1、哨兵模式详解

首先,哨兵是指一个独立进程,他会监控指定的redis服务。当发现主机挂了以后,哨兵会通过一些条件选取一个从机,并将这个从机变成新的主机。

在这里插入图片描述
上图是一个简单的模型,实际上一个哨兵还不够,因为这个哨兵也有挂掉的风险,所以我们还会增加监控哨兵的哨兵,保证系统的运行。一般情况下一个最简单的哨兵模型也应该有三哨兵三机子。

在这里插入图片描述

4.1.1、哨兵判定节点下线

三个哨兵各自监控所有的redis服务,同时也互相监控。

  1. 每个哨兵有一个默认每秒一次的定时任务,去ping所有监控节点(包括哨兵节点),如果哨兵1连续sentinel down-after-milliseconds秒没有ping通某个节点,那这个哨兵1就认为这个节点已掉线。但目前为止只是哨兵1认为这个节点下线,一般称这个节点是哨兵1的主观下线。

    sentinel down-after-milliseconds 可配置,系统默认是60s
  2. 这时系统不会立刻处理节点,因为哨兵1可能判断错误。哨兵1会向其他哨兵发送is-master-down-by-addr来询问他们的看法。其他哨兵也会重复这个流程,直到认为这个节点确实挂了的哨兵数量达到quorum的时候,那系统才会开始处理,这时这个节点被称为客观下线。

    quorum的数量在sentinel moniter master 127.0.0.1 6379 quorum中配置

在这里插入图片描述


4.1.2、哨兵中选举领导者

在这个过程中,首先发现节点下线的哨兵1会被推举成领导者,它在接下来负责主节点的选举。
请添加图片描述


4.1.3、选举主节点

如果下线的是主节点,那哨兵就会开始选举主节点。

首先哨兵会经过下面的判断来决定哪个从节点应该是主节点。

  1. 哨兵有维护一份从节点列表,记录着所有从节点的相关信息。第一步是先过滤掉不健康的节点,哨兵ping从节点经常要花比较长的时间,那这个从节点就算不健康,一般默认超过5s就是不健康。
  2. 之后选择slave-priority最高的从节点,这个可在从节点的配置文件中配置。
  3. 如果还有多个从节点可选,那就选择复制最完整的节点。因为主节点复制数据到从节点是有offset记录数据量的,所以offset最高的节点数据复制最完整。
  4. 如果还有多个节点可选,那就选择最先启动的节点。这里是通过runId判断,runId越小就越早生成。

在这里插入图片描述


4.1.4、新主节点开始接手工作

新的主节点开始接手工作,之后哪怕旧的主节点重新上线,那也只能成为从节点。

  1. 新的主节点执行slaveof no one
  2. 其他从节点执行slaveof newMaster更换主节点。
  3. 之后哨兵通知应用程序新的主节点的地址。

请添加图片描述



4.2、启动哨兵服务

4.2.1、编写哨兵配置文件

配置文件和redis.conf一样,只不过启动的方式不一样。这里我将其命名为是sentinel.conf,放在安装目录下,或者等会启动的时候用指定配置文件的方式启动。

需要注意下面这些配置信息。

# sentinel monitor 主机名(自定义) ip port n; n表示至少要有n个哨兵认为这个监视对象失效,那这台主机才失效。
sentinel monitor master 127.0.0.1 6379 1
# 监控的主机在60000毫秒内没有反馈,那哨兵就认为这台机子挂了
sentinel down-after-milliseconds master 60000
# 要使用空闲的端口号
port 16379



4.2.2、启动哨兵

执行指令redis-sentinel /*/sentinel.conf
fb
需要注意,哨兵监控一个主节点时,会自动监控其从节点。

MacBook-Pro:etc user$ redis-sentinel /usr/local/etc/sentinel.conf
77763:X 14 Feb 2023 00:14:01.952 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
77763:X 14 Feb 2023 00:14:01.952 # Redis version=5.0.6, bits=64, commit=00000000, modified=0, pid=77763, just started
77763:X 14 Feb 2023 00:14:01.952 # Configuration loaded
77763:X 14 Feb 2023 00:14:01.953 * Increased maximum number of open files to 10032 (it was originally set to 2560).
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 5.0.6 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 16379
 |    `-._   `._    /     _.-'    |     PID: 77763
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

77763:X 14 Feb 2023 00:14:01.955 # Sentinel ID is f14ee33db41e8430e3a13154ccfab5f4ea7ed4f6
77763:X 14 Feb 2023 00:14:01.955 # +monitor master reids 127.0.0.1 6379 quorum 1
77763:X 14 Feb 2023 00:14:01.957 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ reids 127.0.0.1 6379



4.2.3、哨兵中的定时任务

  1. 哨兵获取节点拓扑结构:默认哨兵每10s想所有监控节点发送一次info信息,然后这些监控节点回应对应数据。哨兵直接监控的是主节点,配置中sentinel monitor master 127.0.0.1 6379 1只写了主节点的地址,哨兵想要知道主节点有哪些从节点,就需要通过发送info确定节点之间的拓扑结构,这样有新节点加入或者离开时,哨兵也能第一时间知道。
    在这里插入图片描述

  2. 哨兵与主节点信息交换,默认每隔2s哨兵会向主节点发布数据,数据是关于哨兵本身的。同时哨兵也订阅主节点,会从主节点拿到信息。也就是说,哨兵和主节点通过相互订阅发布来交互信息。多个哨兵将自身信息发布到主节点,之后主节点将这些汇总的信息发布给这些哨兵实现信息交流。
    在这里插入图片描述

  1. 检测节点是否在线:默认哨兵会向所有已知节点每秒发送一次ping信息,默认如果连续60s没有ping通一个节点,那就仍未这个节点下线。判定条件可通过sentinel down-after-milliseconds master 3000修改,这条配置表示超过3sping通就判定下线。

在这里插入图片描述




4.3、实例测试

首先启动三个节点,port分别是637963806381

redis-server /usr/local/etc/redis.conf
# another terminal
redis-server /usr/local/etc/redis-slave1.conf
# another terminal
redis-server /usr/local/etc/redis-slave2.conf

并且设6379为主节点。

MacBook-Pro:etc fulanbin$ redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK Already connected to specified master
# another terminal
MacBook-Pro:etc fulanbin$ redis-cli -p 6381
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK Already connected to specified master

开启三个哨兵,port分别是163791648016381。他们的配置文件都写上sentinel monitor mymaster 127.0.0.1 6379 2表示监控主节点6379

redis-sentinel /usr/local/etc/redis-sentinel1.conf
# another terminal
redis-sentinel /usr/local/etc/redis-sentinel2.conf
# another terminal
redis-sentinel /usr/local/etc/redis-sentinel3.conf

之后手动退出6379(关闭端口即可),过一段时间后哨兵16379terminal窗口查看日志(随便找一个哨兵都可查看,他们信息共享),里面记录着选举的整个过程。

从整个日志中可以看到,6381成为了新的主节点。

# 发现6379挂了
69695:X 14 Feb 2023 22:46:27.076 # +sdown master mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:27.160 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2
69695:X 14 Feb 2023 22:46:27.160 # +new-epoch 1
69695:X 14 Feb 2023 22:46:27.160 # +try-failover master mymaster 127.0.0.1 6379
# 通知到其它哨兵,其他哨兵开始投票,比较长的字符串是哨兵的id。哨兵id会自动生成到配置文件中,比如sentinel myid 6a4e23ddd42f1f748016af9318621ec93d59a720
69695:X 14 Feb 2023 22:46:27.164 # +vote-for-leader 6a4e23ddd42f1f748016af9318621ec93d59a720 1
69695:X 14 Feb 2023 22:46:27.167 # 4791869a77100cba19037050216512956d093423 voted for 6a4e23ddd42f1f748016af9318621ec93d59a720 1
69695:X 14 Feb 2023 22:46:27.167 # 5a280e3fc35ca740484ec931a3aa1544baf6f675 voted for 6a4e23ddd42f1f748016af9318621ec93d59a720 1
69695:X 14 Feb 2023 22:46:27.265 # +elected-leader master mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:27.265 # +failover-state-select-slave master mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:27.333 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:27.333 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:27.434 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
# 推举6381为新的主节点
69695:X 14 Feb 2023 22:46:27.553 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:27.553 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:27.642 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:28.272 # -odown master mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:28.587 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:28.587 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:28.641 # +failover-end master mymaster 127.0.0.1 6379
69695:X 14 Feb 2023 22:46:28.641 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381
# 6381成为新的主节点
69695:X 14 Feb 2023 22:46:28.642 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381
69695:X 14 Feb 2023 22:46:28.642 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
69695:X 14 Feb 2023 22:46:58.686 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381

最后连接6381,验证日志内容。

MacBook-Pro:etc user$ redis-cli -p 6381
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=3391124,lag=0
master_replid:fb0f6e5e77e4b460f3950dd43b34231297b253a5
master_replid2:97385f0960597e07bbb059164b2ef7ebfd4aa6a0
master_repl_offset:3391124
second_repl_offset:3208815
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2342549
repl_backlog_histlen:1048576


5、哨兵主从脑裂

现在我们有一主两从,三哨兵的结构。

master与哨兵之间突然网络波动,哨兵集体认为master下线,于是开始选举新的master

在旧的master和哨兵断线,新的master上任前,客户端还能继续向旧的master写数据,因为旧的master只是和哨兵断线但它实际可能还能工作(尽管概率很小)。

那么客户端在旧的master写的数据就会丢失。

这就是哨兵主从脑裂问题。主脑裂开时可能发生的数据丢失。
在这里插入图片描述

5.1、解决方式

我们有两个配置可以减少脑裂发生的概率。

min-replicas-to-write 2
min-replicas-max-lag 10

第一个min-replicas-to-write 2,这个意思是写入的数据至少要同步到3台机器里才算成功。上面的例子中在旧的master在突然掉线时,可能会导致同步失败,那这次写入就失败。

min-replicas-max-lag 10,这时同步的时间,两者结合起来就是在10ms内没有同步到2台机器上这次写就失败。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值