Redis-主从复制和哨兵模式

219 阅读14分钟

Redis-主从复制

基础分析

什么是主从复制

  • Redis的主从复制,实际上就是将一台Redis服务器的数据,复制到其他Redis的服务器。
  • 每台服务器都是一个主节点
  • 一个主节点可以有多个从节点,一个从节点只有一个父节点
  • 主节点以写为主,从节点以读为主

再来一幅图,带你更形象的了解一下主从复制

image.png

为什么要实现主从复制

  • 主从复制可以实现数据备份,这是除了持久化的另一种实现数据保存的方式
  • 实现故障快速修复,因为要实现主从复制必然需要多台服务器,一旦主节点挂掉,从节点可以代替主节点提供读的服务
  • 主从复制配合读写分离,可以实现分担服务器负载,如果在生产环境中读的操作远大于写的操作时,可以通过多个从节点进行分担负载,以提高Redis的并发量
  • 主从复制也是Redis集群搭建和哨兵机制的基础
  • 单个服务器,内存容量是有上限的。实现主从复制,可以减轻负载,从而让服务器不那么容易宕机。

Redis实现主从复制

Redis实现主从复制,最少需要一主二仆,所以我们需要开启三个redis-cli客户端,也需要更改这三个客户端的配置文件

配置文件的修改

  1. 首先,我们要先复制三份配置文件

image.png

  1. 我们选取其中一份作为主节点文件,然后修改另外两份配置文件
  • 修改端口号
  • 修改pidfile文件名称
  • 修改logfile文件名称
  • 修改RDB持久化保存的文件dump.rdb的文件名

启动这三份配置文件对应的redis服务

我们通过info replication命令发现,每台服务器都是主节点

image.png

这时候,假设我们选取6379端口的服务作为主服务器,其他为从。我们就要通过slaveof 主机ip地址 主机端口号这个命令去配置这些仆从服务器

  • 注意:我们是通过命令去设置的,在服务关闭后,它就不再是从机了,要想永久让它变成从机,要在配置文件中配置。

image.png

这样,我们就搭建好了主从复制的集群环境,现在我们来测试一下这个主从复制

主从复制的简单测试

  1. 我们往主机放入一些数据

image.png

  1. 我们在从机读取数据

image.png

image.png

成功实现简单的主从复制~~

那我们如果这时候再去主机改变数据,从机是否也能读取到修改后的值呢?

image.png

答案是可以的~~~

那如果我们这时候把主机的服务关掉,从机还能读取数据吗?

image.png

答案还是可以的~~~ 而且这时候你再去看它们还是不是从机,你会发现,它们还是从机,实现了主机宕机后,用户还能进行读操作,不至于服务全部崩塌。

image.png

那如果我们再在从机尝试写操作,会怎样呢?

image.png

答案是:会报错,从机只能实现读操作

那如果从机宕机了,宕机时,主机进行了一些写操作,宕机了的从机重新连接时,能读到什么数据呢?

模拟宕机:

image.png

模拟宕机后,主机进行了写操作

image.png

模拟从机重新连接

image.png

我们会发现,从机变成了主机,并且保留着宕机前的数据

那如果我们再把它变成从机,它又会怎样?

image.png

我们发现,它拥有了主机所有的数据,这又是为什么呢?

这就涉及到了复制的原理

如果一个Slave指定了一个服务器作为主机,那么主机就会发送一个叫做sync的同步命令,在使用了SLAVEOF命令之后,主机接收到了,就会启动后台的存盘进程,开始收集修改数据集的命令,在存盘进程执行完毕之后,会将数据文件发送给Slave,实现一次完全同步

注意两个复制

  • 全量复制,Slave文件在接到主机发来的数据文件之后,会将其存盘并加载到内存
  • 增量复制,主机和Slave已经实现同步的情况下,如果主机继续修改数据集,会将命令再次收集起来,再发送给Slave

只要是重新连接主机的从机服务器,在连接之后都会自动执行全量复制!!

结论

1、主机意外的挂掉了,那么剩下的从机在主机还没到来之前原地待命,这个时候主机掉了,就意味着失去了写操作。并且主机重新上线之后,还是保持着原来的身份,从机依旧可以获取到主机写入的信息

2、这个时候是如果是从机挂掉了,就代表这个从机已经断开连接,等待再次上线时,就不会连接原来的主机,它自己又变成了主机,但是原先的数据依旧存在,如果其再次重新连接,那么主机当中新添加的数据同样也会被共享到

这时候,大家伙可能会说,如果主机宕机了,从机拥有主机的所有数据,就不能把其中一台从机变成主机,用来实现写操作?而不是什么都不做,白白浪费资源。

哨兵模式出来之前,我们可以通过slaveof no one命令手动来使从机变成主机,然后原先其他从机再手动连接到这台主机。

注意:等到原先主机重新连接的时候,已经变为主机了的从机还是主机,原先的主机就没有了原先属于它的从机,它变成了光杆司令

  • 你可以想象成谋朝篡位

image.png

但是手动的,我相信大家伙都不会喜欢,所以哨兵模式出来了

哨兵模式

简介

什么是哨兵模式呢?

用通俗易懂的话来说,哨兵模式就是Redis会自己创建哨兵进程来监控redis集群中主机的工作状态,一旦主机意外宕机了,哨兵模式可以自己实现主机和从机之间的切换。

工作原理

初理解:

哨兵通过发送命令,等待redis服务器响应,从而监控运行主机和从机。一旦主机宕机,哨兵监控的时候发现了(正常设置多个哨兵,一个哨兵发现的时候,不会马上进行failover,会等多个哨兵也监控到才执行),就会进行投票算法(因为正常是设置多个哨兵,以防只有哨兵的情况下,哨兵也没了就全完了的情况),在从机中选举新的主机。(注意:这时候的宕机的主机再连接回来的话,他只能当选举后的新的主机的从机了,被迫当小弟)

再理解:

  1. 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令
  2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值,则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)。
  3. 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态。
  4. 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
  5. 在一般情况下, 每个Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
  6. 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  7. 没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。 若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。

再来一个图解(master:主机,slave:从机)

image.png

哨兵的作用

  • 哨兵通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器
  • 当哨兵监测到主机宕机,会自动将选举出来的从机切换成主机,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机

Redis实现哨兵模式

Redis实现哨兵模式的配置

  • 哨兵模式的服务-redis-sentinel
  • 哨兵模式的核心文件sentinel.conf
  • 哨兵模式核心文件的核心配置-sentinel monitor 自己取的监控的名字 监控ip地址 监控端口 2(当两个哨兵认为主机宕机了就客观上认为主机宕机了)

实现步骤

  1. 搭建测试环境:一主二从,一哨兵(最低配置)
  2. 一主二从的环境在主从复制搭建了
  3. 搭建一哨兵
    • 在自己编写的redis.conf同级目录下编写sentinel.conf文件

image.png

核心基础配置(其他配置我放到最后

image.png

  1. 通过sudo redis-sentinel myconfig/sentinel.conf启动哨兵模式进行观察

image.png

  1. 将主机shutdown模拟主机宕机,再观察一下,发现6381变成了主机

image.png

image.png

image.png

  1. 试想一下,如果现在主机重新连接回来了,又会变成什么样?

image.png

image.png

结果显示,6379变成了从机~~~

哨兵模式配置文件的其他配置

# Example sentinel.conf

# *** IMPORTANT ***
# 绑定IP地址
# bind 127.0.0.1 192.168.1.1
# 保护模式(是否禁止外部链接,除绑定的ip地址外)
# protected-mode no

# port <sentinel-port>
# 此Sentinel实例运行的端口
port 26379

# 默认情况下,Redis Sentinel不作为守护程序运行。 如果需要,可以设置为 yes。
daemonize no

# 启用守护进程运行后,Redis将在/var/run/redis-sentinel.pid中写入一个pid文件
pidfile /var/run/redis-sentinel.pid

# 指定日志文件名。 如果值为空,将强制Sentinel日志标准输出。守护进程下,如果使用标准输出进行日志记录,则日志将发送到/dev/null
logfile ""

# sentinel announce-ip <ip>
# sentinel announce-port <port>
#
# 上述两个配置指令在环境中非常有用,因为NAT可以通过非本地地址从外部访问Sentinel。
#
# 当提供announce-ip时,Sentinel将在通信中声明指定的IP地址,而不是像通常那样自动检测本地地址。
#
# 类似地,当提供announce-port 有效且非零时,Sentinel将宣布指定的TCP端口。
#
# 这两个选项不需要一起使用,如果只提供announce-ip,Sentinel将宣告指定的IP和“port”选项指定的服务器端口。
# 如果仅提供announce-port,Sentinel将通告自动检测到的本地IP和指定端口。
#
# Example:
#
# sentinel announce-ip 1.2.3.4

# dir <working-directory>
# 每个长时间运行的进程都应该有一个明确定义的工作目录。对于Redis Sentinel来说,/tmp就是自己的工作目录。
dir /tmp

# sentinel monitor <master-name> <ip> <redis-port> <quorum>
#
# 告诉Sentinel监听指定主节点,并且只有在至少<quorum>哨兵达成一致的情况下才会判断它 O_DOWN 状态。
#
#
# 副本是自动发现的,因此您无需指定副本。
# Sentinel本身将重写此配置文件,使用其他配置选项添加副本。另请注意,当副本升级为主副本时,将重写配置文件。
#
# 注意:主节点(master)名称不能包含特殊字符或空格。
# 有效字符可以是 A-z 0-9 和这三个字符 ".-_".
sentinel monitor mymaster 127.0.0.1 6379 2

# 如果redis配置了密码,那这里必须配置认证,否则不能自动切换
# Example:
#
# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd

# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# 主节点或副本在指定时间内没有回复PING,便认为该节点为主观下线 S_DOWN 状态。
#
# 默认是30秒
sentinel down-after-milliseconds mymaster 30000

# sentinel parallel-syncs <master-name> <numreplicas>
#
# 在故障转移期间,多少个副本节点进行数据同步
sentinel parallel-syncs mymaster 1

# sentinel failover-timeout <master-name> <milliseconds>
#
# 指定故障转移超时(以毫秒为单位)。 它以多种方式使用:
#
# - 在先前的故障转移之后重新启动故障转移所需的时间已由给定的Sentinel针对同一主服务器尝试,是故障转移超时的两倍。
#
# - 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#
# - 取消已在进行但未生成任何配置更改的故障转移所需的时间
#
# - 当进行failover时,配置所有slaves指向新的master所需的最大时间。
#   即使过了这个超时,slaves依然会被正确配置为指向master。
#
# 默认3分钟
sentinel failover-timeout mymaster 180000

# 脚本执行
#
# sentinel notification-script和sentinel reconfig-script用于配置调用的脚本,以通知系统管理员或在故障转移后重新配置客户端。
# 脚本使用以下规则执行以进行错误处理:
#
# 如果脚本以“1”退出,则稍后重试执行(最多重试次数为当前设置的10次)。
#
# 如果脚本以“2”(或更高的值)退出,则不会重试执行。
#
# 如果脚本因为收到信号而终止,则行为与退出代码1相同。
#
# 脚本的最长运行时间为60秒。 达到此限制后,脚本将以SIGKILL终止,并重试执行。

# 通知脚本
#
# sentinel notification-script <master-name> <script-path>
#
# 为警告级别生成的任何Sentinel事件调用指定的通知脚本(例如-sdown,-odown等)。
# 此脚本应通过电子邮件,SMS或任何其他消息传递系统通知系统管理员 监控的Redis系统出了问题。
#
# 使用两个参数调用脚本:第一个是事件类型,第二个是事件描述。
#
# 该脚本必须存在且可执行,以便在提供此选项时启动sentinel。
#
# 举例:
#
# sentinel notification-script mymaster /var/redis/notify.sh

# 客户重新配置脚本
#
# sentinel client-reconfig-script <master-name> <script-path>
#
# 当主服务器因故障转移而变更时,可以调用脚本执行特定于应用程序的任务,以通知客户端,配置已更改且主服务器地址已经变更。
#
# 以下参数将传递给脚本:
#
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#
# <state> 目前始终是故障转移 "failover"
# <role> 是 "leader" 或 "observer"
#
# 参数 from-ip, from-port, to-ip, to-port 用于传递主服务器的旧地址和所选副本的新地址。
#
# 举例:
#
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

# 安全
# 避免脚本重置,默认值yes
# 默认情况下,SENTINEL SET将无法在运行时更改notification-script和client-reconfig-script。
# 这避免了一个简单的安全问题,客户端可以将脚本设置为任何内容并触发故障转移以便执行程序。
sentinel deny-scripts-reconfig yes

# REDIS命令重命名
#
#
# 在这种情况下,可以告诉Sentinel使用不同的命令名称而不是正常的命令名称。
# 例如,如果主“mymaster”和相关副本的“CONFIG”全部重命名为“GUESSME”,我可以使用:
#
# SENTINEL rename-command mymaster CONFIG GUESSME
#
# 设置此类配置后,每次Sentinel使用CONFIG时,它将使用GUESSME。 请注意,实际上不需要尊重命令案例,因此在上面的示例中写“config guessme”是相同的。
#
# SENTINEL SET也可用于在运行时执行此配置。
#
# 为了将命令设置回其原始名称(撤消重命名),可以将命令重命名为它自身:
#
# SENTINEL rename-command mymaster CONFIG CONFIG