深入学习 Redis Sentinel - 基于 DockerCompose 编排哨兵分布式架构,理解工作原理

2023-09-13 16:59:06

目录

一、哨兵模式

1.1、为何引入哨兵模式

1.2、Redis Sentinel 分布式架构

1.2.1、概述

1.2.2、工作原理(redis 哨兵的核心功能)

1. 监控:

2. 自动故障转移:

3. 通知

1.2.3、问题:哨兵结点只有一个可以么?

1.3、使用 Docker 和 DockerCompose 模拟部署哨兵模式

1.3.1、前言

1.3.2、准备工作

a)首先要安装好 docker 和 docker-compose.

b)停止之前的 redis 服务器

c)使用 docker 获取 redis 镜像

1.2.3、基于 docker 搭建 redis 哨兵环境

a)分配文件目录结构

b)编写 yml 配置文件

c)编写哨兵结点的三个 conf 配置文件

d)使用 docker-compose 启动 数据结点

e)验证

f)使用 docker-compose 启动 redis-sentinel 结点

日志里为什么全都是报错信息呢?都是什么意思?(重!)

解决方案:

1.2.4、展现哨兵机制

1.2.5、哨兵重新选取主节点的流程

1.2.6、缺陷


一、哨兵模式


1.1、为何引入哨兵模式

实际的开发中,对于服务器后端开发,监控程序,是非常重要的!服务器一般要有比较高的可用性,7 * 24 小时运行,服务器长期运行,总会有一些 “意外” ,具体啥时候出现意外,也不能全靠人工来盯着服务器,所以在早期的主从结构中,会写一个程序来盯着服务器的运行状态.

这个程序需要干两件事:

  1. 监控程序:用来发现服务器运行时出现的异常状态.
  2. 搭配 “报警程序” :通过 短信/电话/邮件/微信/钉钉... 等形式给程序员报警,告诉程序员说,这个服务器程序出问题了!

Ps:互联网公司的程序员,尤其是大厂,公司都会明确要求,程序员手机要 24 小时开机,并且随时关注,报警不仅仅是给这一个程序员,还会给程序员的领导,还有领导的领导~  关键时候错过领导的电话,可能就会有比较负面的评价,升职加薪就要往后了~

程序员如何恢复的?

  1. 先看看主节点还能不能抢救,好不好抢救.
  2. 如果主节点这边出事的原因很难解决,就需要挑一个从节点,设置为新的主节点
    1. 具体的,把选中的从节点,通过 slaveof no one,自立山头.
    2. 其他的从节点,通过修改 slaveof,将 ip 和 port 改为新上任的主节点.
    3. 告知客户端(修改客户端配置),让客户端能够连接新的主节点,用来完成修改数据的操作.
    4. 最后,如果之前挂了的主节点修好了,就可以将其作为一个新的从节点,加入到这个机器当中.

Ps:

1.只要是涉及到人工干预,不说繁琐,至少是很烦人的~

2.另外,这个操作过程一旦出错了,就可能让问题更加严重。

3.通过人工干预的做法,就算程序员第一时间看到了报警信息,第一时间处理,也至少需要半个小时以上的恢复时间,也就是说,这半个小时里,整个 redis 就一直不能写?显然不合适。

为了提高 “可用性” 引入以下架构模式~

1.2、Redis Sentinel 分布式架构

1.2.1、概述

Redis Sentinel 是⼀个分布式架构,其中包含若干个 Sentinel 节点(哨兵)和 Redis 数据节点,这两种结点之间的哨兵机制,是通过独立的进程来体现的,和 redis-server 是不同进程!redis-sentinel 不负责存储数据,只是对其他的 redis-server 进程起到监控的效果.

1.2.2、工作原理(redis 哨兵的核心功能)

1. 监控:

a)redis sentinel 进程,会监控现有的主从结点(这里的监控就是指,sentinel 进程会和 主从结构进程 之间建立 tcp 长连接,通过这样的长连接,定期发送心跳包,看主节点是否挂了,如果 心跳包 没有如果如约而至,就说明 redis 主节点挂了).

b)如果是从节点挂了,其实没关系,如果是主节点挂了,哨兵就要发挥作用了,此时一个哨兵发现了主节点挂了,还不够,需要多个哨兵来认同这件事,主要防止出现误判(网络抖动,导致心跳包丢失).

c)如果主节点确实挂了,这些哨兵结点中,就会选举出一个 leader,由这个 leader 负责从现有的从节点中,挑选出一个新的 主节点.

2. 自动故障转移:

d) 挑选出新的主节点之后,哨兵结点就会自动控制被选中的结点,执行 slaveof no one,让他先自立山头,然后再控制其他从节点,修改 slaveof 到新的主节点上.

3. 通知

e)哨兵结点会自动通知客户端程序,告知新的主节点是谁,后续,客户端再进行写操作,就会针对新的主节点进行操作了.

Ps:以上这三大点,也是 redis 哨兵的核心功能.(这里只是粗略的讲了以下 “哨兵重新选取主节点的流程” ,后面会详细讲!这是面试经常会问的问题!)

1.2.3、问题:哨兵结点只有一个可以么?

redis 哨兵结点,只有一个也是可以的.

但值得注意的是,再分布式系统中,应该避免 “单点” 问题(1.一个服务器挂了,整个就服务就瘫痪了;2.并发量有限).

在 redis 中可能会导致以下问题:

  1. 一个哨兵结点,自身也是容易出现问题的,万一这一个哨兵结点挂了,后续 redis 结点挂了,就无法进行自动恢复了.
  2. 出现误判的概率也比较高,因为网络传输数据是容易出现抖动、延迟、丢包等问题的.

Ps:哨兵结点,最好搞奇数个,最少也要有 3 个

1.3、使用 Docker 和 DockerCompose 模拟部署哨兵模式

1.3.1、前言

这里我们将以下图为例,通过 Docker 和 DockerCompose 部署和编排 3 个哨兵和 1 个主 2 个从结点.

案例说,这 6 个结点是要部署到 6 个不同的服务器主机上的.

但我这里只有一个云服务器(实际的工作中,上述结点放在一个云服务器上事没有意义的,这么做也是没办法,经济有限), 如果直接部署,就需要小心避开这些冲突:端口号、配置文件、数据文件....

使用 docker 就可以有效解决上述问题~ 

虚拟机,就是在电脑上通过软件模拟出另外一些硬件(构造了一个台虚拟电脑),也就是说,通过虚拟机这样的软件,就可以使用一个计算机,来模拟出多个电脑的情况.

但是虚拟机有个很大的问题:很吃配置,这个事情对于我的云服务器来说,压力山大~

docker 可以认为是一个 “轻量级” 的虚拟机(现在后端开发很流行这个组件),既不吃很多的硬件资源,又可以起到虚拟机这样的隔离环境的效果(即使你云服务器配置很低,也能构造出好几个这样的虚拟环境).

1.3.2、准备工作

a)首先要安装好 docker 和 docker-compose.

这里我之前有出过专门的文章,可以去翻翻.

b)停止之前的 redis 服务器
  1. 如果是通过 redis-server 启动服务器,就必须搭配 kill 命令来停止.
  2. 如果是通过 service redis-server start 启动服务器,必须搭配 service redis-server stop 来停止.
  3. 如果使用 kill 命令停止 service redis-server start ,这个 redis-server 进程会自动启动.
c)使用 docker 获取 redis 镜像

通过以下命令,就可以从 docker hb 上拉取 redis 5.0.9 的镜像

docker pull redis:5.0.9

1.2.3、基于 docker 搭建 redis 哨兵环境

Ps:此处涉及到多个 redis server 和多个 redis 哨兵结点,每一个 redis server 和每一个 redis 哨兵结点都是作为一个单独的容器(按照案例,这里总共要部署 6 个容器),为了方便部署,使用 docker-compose 进行容器编排.

a)分配文件目录结构

由于 redis 哨兵结点是单独的 redis 服务器进程,因此之后对于哨兵和主从结点的 yml 配置文件要分开!!!

虽然也可以使用一个 yml 文件 直接启动 6 个容器,但是如果 6 个容器同时启动,可能是 哨兵 先启动完成,数据节点后启动完成,哨兵可能就会先认为是数据结点挂了!虽然从大体上来看不影响,但是会影响到我们对执行日志的观察.

b)编写 yml 配置文件

这里分别在 redis-data 目录 和 redis-sentinel 目录下创建一个 yml 配置文件(注意,文件名必须是 docker-compose.yml)

分别用来描述 3 个数据结点和 3 个哨兵结点 , 具体要创建哪些容器,每个容器运行的各种参数,描述清除。

后续通过一个简单的命令,就可以批量进行 启动/停止 这些容器了.

Ps:下来讲到的配置文件不需要记,只需要了解其中一些参数的意思即可,实际工作中不可能让你去写,只会让你去 copy 现有的,对关键参数进行修改.

数据结点配置文件如下:

version: '3.7'
services:
  master:
    image: 'redis:5.0.9'
    container_name: redis-master
    restart: always
    command: redis-server --appendonly yes
    ports:
      - 6379:6379
  slave1:
    image: 'redis:5.0.9'
    container_name: redis-slave1
    restart: always
    command: redis-server --appendonly yes --slaveof redis-master 6379
    ports:
      - 6380:6379
  slave2:
    image: 'redis:5.0.9'
    container_name: redis-slave2
    restart: always
    command: redis-server --appendonly yes --slaveof redis-master 6379
    ports:
      - 6381:6379

对一些关键参数的解释:

  • image:当前容器是基于哪个镜像创建的(镜像就相当于模板,启动镜像就可以构建出容器).
  • container_name:自定义容器的名字。docker 中可以通过容器名字, 作为 ip 地址, 进⾏相互之间的访问.
  • restart:容器遇到一些异常情况终止了,是否重启(always 表示一旦遇到异常情况,立刻重启 ).
  • command:用什么命令来启动服务.
  • ports:这里的规则是 [宿主机端口] [容器内部端口]。上述配置文件中,要启动三个容器(master、slave1、slave2),这三个容器的内部端口号都是自成一个小天地,也就是说,容器 1 的 6379 和 容器 2 的 6379 之间是不会有冲突的(两个容器可以视为两个主机);有的时候,希望容器外访问容器内部的端口,需要进行端口映射,把容器内吨端口映射到宿主机上,后续访问宿主机这个端口,就相当于在访问对应容器的对应端口了.

Ps:站在宿主的角度,访问上述几个端口的时候,也不知道这个端口是一个宿主机上的服务,还是来自于容器内部的服务,只要正常使用即可。这里的映射过程很像 NAT.

哨兵结点配置文件如下:

version: '3.7'
services:
  sentinel1:
    image: 'redis:5.0.9'
    container_name: redis-sentinel-1
    restart: always
    command: redis-sentinel /etc/redis/sentinel.conf
    volumes:
      - ./sentinel1.conf:/etc/redis/sentinel.conf
    ports:
      - 26379:26379
  sentinel2:
    image: 'redis:5.0.9'
    container_name: redis-sentinel-2
    restart: always
    command: redis-sentinel /etc/redis/sentinel.conf
    volumes:
      - ./sentinel2.conf:/etc/redis/sentinel.conf
    ports:
      - 26380:26379
  sentinel3:
    image: 'redis:5.0.9'
    container_name: redis-sentinel-3
    restart: always
    command: redis-sentinel /etc/redis/sentinel.conf
    volumes:
      - ./sentinel3.conf:/etc/redis/sentinel.conf
    ports:
      - 26381:26379

 对一些关键参数的解释:

volumes:建立映射. 哨兵结点在运行的过程中,会对配置文件进行自动修改,因此就不能只拿 /etc/redis/sentinel.conf 这一个配置文件,给三个容器分别进行映射. 以上 volumes 的内容,就需要我们在当前目录下(redis-sentinel目录下)继续创建三个 conf 文件.

c)编写哨兵结点的三个 conf 配置文件

创建 sentinel1.conf、sentinel2.conf、sentinel2.conf 这三个配置文件,内容可以是一样的,容器启动后,会自动对这三个 conf 文件进行修改.

bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000

参数解释:

  • bind 0.0.0.0:表示让其他结点进行访问.
  • port:容器内部使用的端口.
  • sentinel monitor redis-master 6379 2:这里是告诉哨兵结点,需要监控哪个 redis 服务器. redis-master 这里其实是 ip 地址,是使用 docker 自动进行域名解析. 最后的 2 表示法定票数,这里的票数就是为了更稳健的确认,当前 redis-server 是否挂了,不能只听一个哨兵的一面之词.
  • sentinel down-after-milliseconds redis-master 1000:这里表示心跳包的超时时间.(此处是 1000ms).
d)使用 docker-compose 启动 数据结点

使用 docker-compose up -d 命令(-d 表示后天运行)启动所有容器(必须和 docker-compose.yml 同文件路径下)

Ps:如果启动后发现前面配置有误,需要重新操作,使用 docker-compose down 即可停止刚创建好的容器.

如果出现以下错误,说明 yml 中配置的 version 不支持,修改成报错信息中支持的版本即可(以下报错中提示,只支持 version 为 2.2 或者 3.3 的版本)

如下信息为启动成功

通过 redis-compose logs 命令查看运行日志信息

e)验证

通过连接 redis 验证主从结构

连接主节点:redis-cli -p 6379

连接第一个从节点:redis-cli -p 6380

连接第二个从节点:redis-cli -p 6381

f)使用 docker-compose 启动 redis-sentinel 结点

在 redis-sentine 目录下,使用 docker-compose up -d 启动所有容器

通过 docker-compose logs 查看日志文件

日志里为什么全都是报错信息呢?都是什么意思?(重!)

docker-compose 一下启动了 N 个容器,此时 N 个容器都是处于同一个 “局域网” 中,可以使这 N个容器之间可以互相访问~

但是!!! 三个 redis-server 结点是一个局域网,三个哨兵结点是另外一个局域网,默认情况下,这两网络是不互通的!!!

解决方案:

可以使用 docker-compose 把此处两组服务放到同一个局域网中.

具体的,使用 docker network ls 列出当前 docker 中的局域网,就可以拿到 redis-data 服务的 docker-compose 文件所在目录名(用来修改配置文件)

修改哨兵结点中配置文件,在之前配置文件的基础上加上如下配置:

networks:
  default:
    external:
      name: redisdata_default

然后再启动哨兵,观察日志如下:

打开 sentinel1.conf 文件,就可以看到 ,哨兵结点启动之后,自动进行修改的内容如下:

1.2.4、展现哨兵机制

哨兵存在的意义,就是在 redis 主从机构出现问题的时候(主节点挂了),此时哨兵结点能够自动帮我我们重新选出一个主节点,来代替之前挂了的结点,保证整个 redis 仍然是可用的状态.

这里我们可以通过 docker stop redis-master  命令手动把主节点干掉,然后观察哨兵日志,可以看到

  1. sdown 主观下线:本哨兵结点,认为该主节点挂了.
  2. odown 客观下线:好几个哨兵都认为该主节点挂了,也就是达到了法定票数,此时这个主节点挂了的事情就被实锤了.

此时就需要先选出一个 leader哨兵,由这个 leader 哨兵结点选出一个从节点,作为新的主节点.

接着往下看日志,就可以看出 3 个哨兵的投票过程.

1.2.5、哨兵重新选取主节点的流程

1. 主观下线(sdown):哨兵节点通过心跳包,判定 redis 服务器是否正常工作. 如果心跳包没有如约而至,就说明 redis 服务器挂了.

Ps:此时还不能排除网络波动的影响,因此就只能单方面的认为这个 redis 结点挂了.

比如是否可能出现非常严重的网络波动,导致所有哨兵都联系不上 redis 主节点,误判成挂了呢?

当然可能是有的!如果出现这个情况,怕是用户的客户端也连接不上 redis 主节点,此时这个主节点基本上也就无法正常工作了.

“挂了” 不一定是进程崩了,只要无法正常访问,都可以视为挂了.

2. 客观下线(odown):多个哨兵都认为主节点挂了,(认为挂了的哨兵数目到达 “法定票数”),哨兵们就认为这个主节点是 客观下线.

3. 多个哨兵结点会通过投票的方式,选出一个 leader 哨兵结点,有这个 leader 负责选出一个 从节点 作为新的主节点.

具体的,每个哨兵手里只有一票(接下来的投票过程,就是看谁反应快,网络延迟小)

1 号哨兵 第一个发现当前是客观下线之后,就立即给自己投了一票(推举自己成为 leader),并且告诉 2 3 ,我来负责这个事情(2 3 当他们没有投出这一票的时候,拉票请求,就会投出去,如果有多个拉票请求,就投给最先到达的) ,如下:

2 号哨兵不乐意,认为自己和 1 号同时发现,也给自己投了一票,3 号哨兵慢了半拍,才发现是客观下线,就把这一票投给了 1 号哨兵,如下:

 如果总的票数到达了哨兵总数的一半,选举就完成了.(把哨兵个数设置成奇数个结点,就是为了方便投票).

4. 此时 leader 选举完毕,leader 需要挑选出一个从节点,作为新的主节点.

具体的挑选从节点的规则如下:

a)优先级:每个 redis 数据结点,都会在配置文件中有一个优先级的设置(slave-priority)优先级高的从节点,就会胜出(如果没有设置,默认优先级都是一样的).  如果当前优先级一样,就看下一个规则.

b)offset :offset 就是从节点从主节点这边同步数据的进度,数值越大,说明从结点的数据和主节点的数据越接近,因此,最大的胜出.  如果当前优先级一样,就看下一个规则.

c)run id:每个 redis 结点启动的时候随机生成一串数字(大小全随机),这时候就是相当于是随机了.

这就像是,大学的学生如果和辅导员有亲戚关系,那么班长就是钦定的,如果没有关系,那么就看谁更听她的话,如果都是刺头,那就只能看谁名字好听了~

5. 新的主节点指定好了之后,leader 就会控制这个结点,执行 slave no one,让其独立山头,成为 master,然后再控制其他节点,执行 slave of,让其他节点以新的 master 作为主节点.

6. 最后,如果之前挂掉的主节点修复了,就直接让这个节点变为从节点加入到机器中(为什么不在成为主节点?因为成为主节点,还需要通过 slave of 修改正在运行的主节点,这个过程,可能会丢失数据).

使用 docker start redis-master 命令启动恢复之前挂掉的主节点后,会发现,已经变为从节点

1.2.6、缺陷

哨兵 + 主从解决的问题是 “提高可用性”,不能解决极端情况下写丢失的问题~

最关键的一点就是,在数量十分庞大的情况下,这种模式就难以胜任了!

因此,redis 集群,就是解决存储容量问题的有效方案.

更多推荐

招股书更新9版终上市,飞沃科技能否躲过风电红利后的黯淡?

文丨熔财经作者丨文泽碳达峰、碳中和成为主旋律目标下,作为可再生能源主力的风电产业迎来了发展的“黄金时代”。与新能源相关的上下游企业也赚的“盆满钵满”。在此背景下,飞沃科技(301232.SZ)历经4轮问询,更新9版招股书终于登陆资本市场。从业务布局与业绩表现来看,飞沃科技具备“小巨人”的典型特征:在细分领域表现突出、竞

APSIM模型的生育期影响因子及算法

为什么种植和收获时间改了,图表还是不对应??那么就涉及到调节生育期相关参数APSIM模型是作物模型领域实践最广泛的模型。DNDC模型、DSSAT模型、AQUACROP模型、WOFOST模型、SICTS模型、PCSE模型也是非常热门APSIM(AgriculturalProductionSystemssIMulator)

ONES 全球化启航,用软件服务全球企业

美西太平洋时间2023年9月6日至9月8日,SaaStrAnnual2023大会在美国旧金山举办。作为全球最大规模、最具影响力的SaaS行业盛会,SaaStr吸引了上万名来自世界各地的SaaS行业从业者,ONES也作为展商之一参与其中。在为期三天的大会期间,ONES展位迎来了大量的SaaS优秀同行、企业管理者和投资人,

Fast-DDS 服务发现简要概述

阅读本文章需要对DDS基础概念有一些了解,一些内容来自Fast-DDS官方文档,一些是工作中踩过的坑。1.服务发现阶段满足OMG标准的DDS服务发现分为两部分,分别是:PDP(ParticipantDiscoveryProtocol参与者发现协议):参与者确认彼此的存在。参与者会定期发送公告信息,消息包括但不限于参与者

【2023最新Java面试宝典】—— SpringBoot面试题(44道含答案)

1.什么是SpringBoot?SpringBoot是Spring开源组织下的子项目,是Spring组件一站式解决方案,主要是简化了使用Spring的难度,简省了繁重的配置,提供了各种启动器,使开发者能快速上手。2.为什么要用SpringBoot快速开发,快速整合,配置简化、内嵌服务容器3.SpringBoot与Spr

Java并发编程第8讲——ThreadLocal详解

ThreadLocal无论是在项目开发还是面试中都会经常碰到,它的重要性可见一斑,本篇文章就从ThreadLocal的使用、实现原理、核心方法的源码、内存泄漏问题等展开介绍一下。一、什么是ThreadLocalThreadLocal是java.lang下面的一个类,在JDK1.2版本加入,作者是JoshBloch(集合

华为云云耀云服务器L实例评测|轻量级应用服务器对决:基于 fio 深度测评华为云云耀云服务器L实例的磁盘性能

本文收录在专栏:#云计算入门与实践-华为云专栏中,本系列博文还在更新中相关华为云云耀云服务器L实例评测文章列表如下:华为云云耀云服务器L实例评测|从零开始:云耀云服务器L实例的全面使用解析指南华为云云耀云服务器L实例评测|轻量级应用服务器对决:基于Geekbench深度测评华为云云耀云服务器L实例的处理器性能华为云云耀

基于STC15单片机-LM35-DS8B20温度测量-DS1302计时-proteus仿真-源程序

一、系统方案1、本设计采用STC15单片机作为主控器。2、DS18B20采集温度值送到液晶1602显示。3、DS1302计时,日期送到液晶1602显示。4、LM35采集另一路温度值送到数码管显示。二、硬件设计原理图如下:三、单片机软件设计1、首先是系统初始化/IO初始化为准双向/voidIO_Init(){P0M0=0

Redis的介绍,安装Redis的方式

🐌个人主页:🐌叶落闲庭💨我的专栏:💨c语言数据结构javaEE操作系统石可破也,而不可夺坚;丹可磨也,而不可夺赤。Redis初识Redis1.1认识Redis1.2安装Redis的方式1.2.1安装Redis依赖1.2.2上传安装包并解压1.2.3启动Redis1.2.3.1默认启动1.2.3.2指定配置启动1

自动化测试:yaml结合ddt实现数据驱动!

在python+unittest+selenium+ddt的框架中,数据驱动常见有以下几种方式实现:Csv/txtExcelYAML本文主要给大家介绍测试数据存储在YAML文件中的使用场景。首先先来简单介绍一下YAML。1.什么是YAML一种标记语言类似YAML,它实质上是一种通用的数据串行化格式,由于其可读性高,用来

安装配置 IDE

目录WebStormSublimeText3安装配置subl快捷命令(OSX)详细过程分解安装PackageControl安装配置主题常用插件Atom插件列表/PluginList推荐配置keymap.csonVisualStudioCode配置按键插件Cursor适合前端、后端、全栈工程师,尤其以Javascript

热文推荐