写点什么

Redis-Sentinel 深入浅出原理和实战

发布于: 2021 年 04 月 12 日
Redis-Sentinel 深入浅出原理和实战

本篇博客会简单的介绍 Redis 的 Sentinel 相关的原理,同时也会在最后的文章给出硬核的实战教程,让你在了解原理之后,能够实际上手的体验整个过程。


之前的文章聊到了 Redis 的主从复制,聊到了其相关的原理和缺点,具体的建议可以看看我之前写的文章Redis的主从复制


总的来说,为了满足 Redis 在真正复杂的生产环境的高可用,仅仅是用主从复制是明显不够的。例如,当 master 节点宕机了之后,进行主从切换的时候,我们需要人工的去做 failover。


同时在流量方面,主从架构只能通过增加 slave 节点来扩展读请求,写能力由于受到 master 单节点的资源限制是无法进行扩展的。


这也是为什么我们需要引入 Sentinel。

Sentinel

功能概览

Sentinel 其大致的功能如下图。



Sentinel 是 Redis 高可用的解决方案之一,本身也是分布式的架构,包含了多个 Sentinel 节点和多个 Redis 节点。而每个 Sentinel 节点会对 Redis 节点和其余的 Sentinel 节点进行监控。


当其发现某个节点不可达时,如果是 master 节点就会与其余的 Sentinel 节点协商。当大多数的 Sentinel 节点都认为 master 不可达时,就会选出一个 Sentinel 节点对 master 执行故障转移,并通知 Redis 的调用方相关的变更。


相对于主从下的手动故障转移,Sentinel 的故障转移是全自动的,无需人工介入。

Sentinel 自身高可用

666,那我怎么知道满足它自身的高可用需要部署多少个 Sentinel 节点?


因为 Sentinel 本身也是分布式的,所以也需要部署多实例来保证自身集群的高可用,但是这个数量是有个最低的要求,最低需要 3 个


我去,你说 3 个就 3 个?我今天偏偏就只部署 2 个


你别杠...等我说了为什么就必须要 3 个...


因为哨兵执行故障转移需要大部分的哨兵都同意才行,如果只有两个哨兵实例,正常运作还好,就像这样。


<img src="https://tva1.sinaimg.cn/large/0081Kckwgy1glf2ztrzuxj30uc0e0tad.jpg" alt="redis-sentinel" style="zoom: 67%;" />


如果哨兵所在的那台机器由于机房断电啊,光纤被挖啊等极端情况整个挂掉了,那么另一台哨兵即使发现了 master 故障之后想要执行故障转移,但是它无法得到任何其余哨兵节点的同意,此时也永远无法执行故障转移,那 Sentinel 岂不是成了一个摆设?


所以我们需要至少 3 个节点,来保证 Sentinel 集群自身的高可用。当然,这三个 Sentinel 节点肯定都推荐部署到不同的机器上,如果所有的 Sentinel 节点都部署到了同一台机器上,那当这台机器挂了,整个 Sentinel 也就不复存在了。


<img src="https://tva1.sinaimg.cn/large/0081Kckwgy1glf3ho05rwj31a20pkgp4.jpg" alt="redis-sentinel-success" style="zoom:67%;" />

quorum&majority

大部分?大哥这可是要上生产环境,大部分这个数量未免也太敷衍了,咱就不能专业一点?


前面提到的大部分哨兵同意涉及到两个参数,一个叫quorum,如果 Sentinel 集群有quorum个哨兵认为 master 宕机了,就客观的认为 master 宕机了。另一个叫majority...


等等等等,不是已经有了一个叫什么 quorum 的吗?为什么还需要这个 majority?


你能不能等我把话说完...


quorum刚刚讲过了,其作用是判断 master 是否处于宕机的状态,仅仅是一个判断作用。而我们在实际的生产中,不是说只判断 master 宕机就完了, 我们不还得执行故障转移,让集群正常工作吗?


同理,当哨兵集群开始进行故障转移时,如果有majority个哨兵同意进行故障转移,才能够最终选出一个哨兵节点,执行故障转移操作。

主观宕机 &客观宕机

你刚刚是不是提到了客观宕机?笑死,难不成还有主观宕机这一说?



Sentinel 中认为一个节点挂了有两种类型:


  • Subjective Down,简称 sdown,主观的认为 master 宕机

  • Objective Down,简称 odown,客观的认为 master 宕机


当一个 Sentinel 节点与其监控的 Redis 节点 A 进行通信时,发现连接不上,此时这个哨兵节点就会主观的认为这个 Redis 数据 A 节点 sdown 了。为什么是主观?我们得先知道什么叫主观


未经分析推算,下结论、决策和行为反应,暂时不能与其他不同看法的对象仔细商讨,称为主观


简单来说,因为有可能只是当前的 Sentinel 节点和这个 A 节点的网络通信有问题,其余的 Sentinel 节点仍然可以和 A 正常的通信。


<img src="https://tva1.sinaimg.cn/large/0081Kckwgy1glhcj19q37j318o0lmgnb.jpg" alt="sentinel-sdown" style="zoom:50%;" />


这也是为什么我们需要引入 odown,当大于等于了 quorum 个 Sentinel 节点认为某个节点宕机了,我们就客观的认为这个节点宕机了。


当 Sentinel 集群客观的认为 master 宕机,就会从所有的 Sentinel 节点中,选出一个 Sentinel 节点,来最终执行 master 的故障转移。


那这个故障转移具体要执行些什么操作呢?我们通过一个图来看一下。


<img src="https://tva1.sinaimg.cn/large/0081Kckwgy1glg76hj320j31cm0l240z.jpg" alt="sentinel-ops" style="zoom:67%;" />


通知调用的客户端 master 发生了变化


通知其余的原 slave 节点,去复制 Sentinel 选举出来的新的 master 节点


如果此时原来的 master 又重新恢复了,Sentinel 也会让其去复制新的 master 节点。成为一个新的 slave 节点。

硬核教程

硬核教程旨在用最快速的方法,让你在本地体验 Redis 主从架构和 Sentinel 集群的搭建,并体验整个故障转移的过程。

前置要求

  1. 安装了 docker

  2. 安装了 docker-compose

准备 compose 文件

首先需要准备一个目录,然后分别建立两个子目录。如下。


$ tree ..├── redis│   └── docker-compose.yml└── sentinel    ├── docker-compose.yml    ├── sentinel1.conf    ├── sentinel2.conf    └── sentinel3.conf
2 directories, 5 files
复制代码

搭建 Redis 主从服务器

redis 目录下的docker-compose.yml内容如下。


version: '3'services:  master:    image: redis    container_name: redis-master    ports:      - 6380:6379  slave1:    image: redis    container_name: redis-slave-1    ports:      - 6381:6379    command:  redis-server --slaveof redis-master 6379  slave2:    image: redis    container_name: redis-slave-2    ports:      - 6382:6379    command: redis-server --slaveof redis-master 6379
复制代码


以上的命令,简单解释一下 slaveof

就是让两个 slave 节点去复制 container_name 为 redis-master 的节点,这样就组成了一个简单的 3 个节点的主从架构


然后用命令行进入当前目录,直接敲命令docker-compose up即可,剩下的事情交给 docker-compose 去做就好,它会把我们所需要的节点全部启动起来。


此时我们还需要拿到刚刚我们启动的 master 节点的 IP,简要步骤如下:


  1. 通过docker ps找到对应的 master 节点的 containerID


   $ docker ps   CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES   9f682c199e9b        redis               "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:6381->6379/tcp   redis-slave-1   2572ab587558        redis               "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:6382->6379/tcp   redis-slave-2   f70a9d9809bc        redis               "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds        0.0.0.0:6380->6379/tcp   redis-master
复制代码


也就是f70a9d9809bc


  1. 通过docker inspect f70a9d9809bc,拿到对应容器的 IP,在 NetworkSettings -> Networks -> IPAddress 字段。


然后把这个值给记录下来,此处我的值为172.28.0.3

搭建 Sentinel 集群

sentinel 目录下的docker-compose.yml内容如下。


version: '3'services:  sentinel1:    image: redis    container_name: redis-sentinel-1    ports:      - 26379:26379    command: redis-sentinel /usr/local/etc/redis/sentinel.conf    volumes:      - ./sentinel1.conf:/usr/local/etc/redis/sentinel.conf  sentinel2:    image: redis    container_name: redis-sentinel-2    ports:    - 26380:26379    command: redis-sentinel /usr/local/etc/redis/sentinel.conf    volumes:      - ./sentinel2.conf:/usr/local/etc/redis/sentinel.conf  sentinel3:    image: redis    container_name: redis-sentinel-3    ports:      - 26381:26379    command: redis-sentinel /usr/local/etc/redis/sentinel.conf    volumes:      - ./sentinel3.conf:/usr/local/etc/redis/sentinel.confnetworks:  default:    external:      name: redis_default
复制代码


同样在这里解释一下命令

redis-sentinel 命令让 redis 以 sentinel 的模式启动,本质上就是一个运行在特殊模式的 redis 服务器。

和 redis-server 的区别在于,他们分别载入了不同的命令表,sentinel 中无法执行各种 redis 中特有的 set get 操作。


建立三份一模一样的文件,分别命名为 sentinel1.conf、sentinel2.conf 和 sentinel3.conf。其内容如下:


port 26379dir "/tmp"sentinel deny-scripts-reconfig yessentinel monitor mymaster 172.28.0.3 6379 2sentinel config-epoch mymaster 1sentinel leader-epoch mymaster 1
复制代码


可以看到,我们对于 sentinel 的配置文件中,sentinel monitor mymaster 172.28.0.3 6379 2表示让它去监听名为mymaster的 master 节点,注意此处的 IP 一定要是你自己 master 节点的 IP,然后最后面的2就是我们之前提到的quorum


然后命令行进入名为 sentinel 的目录下,敲docker-compose up即可。至此,Sentinel 集群便启动了起来。

手动模拟 master 挂掉

然后我们需要手动模拟 master 挂掉,来验证我们搭建的 Sentinel 集群是否可以正常的执行故障转移。


命令行进入名为 redis 的目录下,敲入如下命令。


docker-compose pause master
复制代码


此时就会将 master 容器给暂停运行,让我们等待 10 秒之后,就可以看到 sentinel 这边输出了如下的日志。


redis-sentinel-2 | 1:X 07 Dec 2020 01:58:05.459 # +sdown master mymaster 172.28.0.3 6379..................redis-sentinel-1 | 1:X 07 Dec 2020 01:58:06.932 # +switch-master mymaster 172.28.0.3 6379 172.28.0.2 6379
复制代码


得得得,你干什么就甩一堆日志文件上来?凑字数?你这样鬼能看懂?


的确,光从日志文件一行一行的看,就算是我自己过两周再来看,也是一脸懵逼。日志文件完整了描述了整个 Sentinel 集群从开始执行故障转移到最终执行完成的所有细节,但是在这里直接放出来不方便大家的理解。


所以为了让大家能够更加直观的了解这个过程,我简单的把过程抽象了成了一张图,大家看图结合日志,应该能够更容易理解。



里面关键的步骤步骤的相关解释我也一并放入了图片中。


最终的结果就是,master 已经从我们最开始的172.28.0.3切换到了172.28.0.2,后者则是原来的 slave 节点之一。此时我们也可以连接到172.28.0.2这个容器里去,通过命令来看一下其现在的情况。


role:masterconnected_slaves:1slave0:ip=172.28.0.4,port=6379,state=online,offset=18952,lag=0master_replid:f0bf5d1c843ec3ab005c5ac2b864f7ffdc6a8217master_replid2:72c43e1f9c05d4b08bea6bf9b2549997587e261cmaster_repl_offset:18952second_repl_offset:16351repl_backlog_active:1repl_backlog_size:1048576repl_backlog_first_byte_offset:1repl_backlog_histlen:18952
复制代码


可以看到,现在的172.28.0.2这个节点的角色已经变成了 master,与其相连接的 slave 节点只有 1 个,因为现在的原 master 还没有启动起来,总共存活的只有 2 个实例。

原 master 重启启动

接下来我们模拟原 master 重新启动,来看一下会发什么什么。


还是通过命令行进入到名为 redis 的本地目录,通过docker-compose unpause master来模拟原 master 故障恢复之后的上线。同样我们连接到原 master 的机器上去。


$ docker exec -it f70a9d9809bc1e924a5be0135888067ad3eb16552f9eaf82495e4c956b456cd9 /bin/sh; exit# redis-cli127.0.0.1:6379> info replication# Replicationrole:slavemaster_host:172.28.0.2master_port:6379master_link_status:up......
复制代码


master 断线重连之后,角色也变成了新的 master(也就是172.28.0.2这个节点)的一个 slave。


然后我们也可以通过再看一下新 master 节点的 replication 情况作证。


# Replicationrole:masterconnected_slaves:2slave0:ip=172.28.0.4,port=6379,state=online,offset=179800,lag=0slave1:ip=172.28.0.3,port=6379,state=online,offset=179800,lag=1......
复制代码


原 master 短线重连之后,其 connected_slaves 变成了 2,且原 master172.28.0.3被清晰的标注为了 slave1,同样与我们开篇和图中所讲的原理相符合。


欢迎微信搜索关注【SH 的全栈笔记】,回复【队列】获取 MQ 学习资料,包含基础概念解析和 RocketMQ 详细的源码解析,持续更新中。

好了以上就是本篇博客的全部内容了,如果你觉得这篇文章对你有帮助,还麻烦点个赞关个注分个享留个言



发布于: 2021 年 04 月 12 日阅读数: 111
用户头像

公众号【SH的全栈笔记】 2018.10.17 加入

还未添加个人简介

评论

发布
暂无评论
Redis-Sentinel 深入浅出原理和实战