Redis (十五) 哨兵机制
文章目录
- 前言
- 什么是哨兵机制
- 如何实现哨兵机制
- 什么是 Docker
- 使用docker搭建redis哨兵环境
- 哨兵节点选出新的主节点的过程
- 总结
前言
前面我们学习了关于 Redis 主从复制的问题,主从复制解决的是 Redis 服务器的单点问题,但是解决的主要也是读操作问题,如果 Redis 主节点挂掉了之后,那么整个 Redis 服务就只能进行读操作,而无法进行写操作了。当主节点挂掉之后,只能通过人工的方式,从从节点中选出一个节点作为主节点,然后修改其他从节点的主节点为当前节点才可以,但是既然是需要人为操作的,服务器的工作时间是 7 * 24 小时的,而人不可能全天都可以工作,所以当主节点挂掉之后,一定时间之内是无法完成修复的,也就意味着这一段时间之后是无法进行写操作的,这样造成的损失肯定是很大的。所以为了解决这个问题,就使用了哨兵机制。
什么是哨兵机制
哨兵机制是通过独立的进程来体现的,Redis 哨兵机制就是有一个独立的进程负责监视 Redis 进程,当 Redis 进程出现了异常之后,这个哨兵就会及时的发现问题并且解决这个问题。
往往哨兵节点的个数应该至少是 3 个,因为如果是一个哨兵节点的话,那么这个哨兵节点挂掉了之后的话,也就没有哨兵对 Redis 节点进行监视了,那么为什么不是 2 个而是三个呢?因为哨兵节点的个数应尽量是奇数个,这里是为了后面哨兵节点选出 leader 更方便,后面为大家详细介绍。
这些哨兵节点是独立于 redis-server 进程运行的进程,这些哨兵节点会对 redis 主节点和从节点进行监视。如果发现从节点挂掉之后,其实影响不大,但是哨兵还是会在日志中记录哪个从节点出现了故障,当我们程序员发现了之后可以对其进行维修。
而如果是主节点出现了故障挂掉之后,哨兵就会发挥他们的作用:
- 当一个哨兵节点发现主节点挂掉之后,此时是不够的,因为可能因为网络的问题出现误判的情况,所以这个哨兵就会寻求其他哨兵的意见,如果其他的哨兵也发现了主节点挂掉之后,才会真正的采取措施。
- 当证实了主节点挂掉之后,这些哨兵节点就会推举出来一个 leader,然后这个 leader 就会从现有的从节点中挑选出来一个节点作为新的主节点。
- 当选出来新的主节点之后,哨兵节点就会控制新的主节点执行 slaveof no one 操作,使之称为一个主节点,然后其他的从节点修改 slaveof 到这个新的主节点之上。
- 哨兵节点会自动的通知客户端程序,告诉我们新的主节点是谁,后续客户端再进行写操作的时候就会针对这个新的主节点进行操作了。
总结来说,哨兵的主要功能就是:
- 监视
- 自动故障转移
- 通知
如何实现哨兵机制
按理来说,既然是分布式系统就应该需要多台主机,但是因为我实力有限,只有一台云服务器,所以如何实现我就在一台云服务器上面模拟出来。
那么如何在一台主机上模拟出多台 redis 服务器和哨兵的情景呢?我们可以参照前面主从复制时候配置多台 redis 服务器的做法,但是这样比较麻烦,所以这里我选择的方法是使用 docker 的方式来实现。
什么是 Docker
这里只是简单的为大家说明一下什么是 docker:
Docker是一个开源的应用容器引擎,它允许开发者将应用及其依赖打包到一个可移植的容器中,并发布到任何流行的Linux或Windows操作系统的机器上。这个容器是完全使用沙箱机制,相互之间不会有任何接口。它的主要目的是让开发者能够更轻松地打包、发布和运行他们的应用程序。
docker 也可以认为是一个“轻量级”的虚拟机,但是它又不像虚拟机那样需要吃很多的硬件资源,所以就算在配置比较低的云服务上面也能够构造出几个这样的虚拟环境。
docker 中包含两个重要的概念:镜像和容器:
- Docker镜像:Docker镜像是一个只读的模板,包含了运行某个应用所需的所有代码、库、环境变量和配置文件。你可以将Docker镜像看作是一个应用程序的“集装箱”,里面包含了运行该应用程序所需的所有“货物”。
- Docker容器:Docker容器则是基于Docker镜像创建的运行实例。你可以将Docker容器看作是使用Docker镜像创建的“集装箱货车”,它包含了运行应用程序所需的所有环境和依赖。
docker 中的镜像和容器就类似于可执行程序和进程的关系。
要想使用 docker,首先需要先下载 docker:
root@iZ2ze5bzkbeuwwqowjzo27Z:~# apt list docker.io Listing... Done docker.io/jammy-updates,now 24.0.5-0ubuntu1~22.04.1 amd64 [installed] N: There are 2 additional versions. Please use the '-a' switch to see them. root@iZ2ze5bzkbeuwwqowjzo27Z:~# apt install docker.io
安装完成之后,输入 docker 显示下面内容说明安装 docker 成功:
安装完成 docker 之后还需要安装 docker-compose:
apt install docker-compose
当安装完成 docker 和 docker-compose 之后,我们需要先停止之前的 redis-server:
# 停止redis-server service redis-server stop # 停止redis-sentinel,如果之前有的话 service redis-sentinel stop
然后通过 docker 获取 redis 镜像:
docker pull redis:redis版本号
上面拉取到的镜像,里面包含一个精简的 Linux 系统,并且上面安装了 redis,只要基于这个镜像创建一个容器跑起来,此时 redis 服务器就搭建好了。
可以使用 docker images 查看当前存在的 docker 镜像:
root@iZ2ze5bzkbeuwwqowjzo27Z:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE redis 6.0.16 b0f8d8ac93c5 15 months ago 112MB
使用docker搭建redis哨兵环境
当安装完成 docker 并且 pull 到了 redis 容器之后,我们就可以通过 docker 来搭建 redis 哨兵环境了。
每一个 redis-server 和 redis-sentinel 都是一个作为一个单独的容器,可以一个一个启动它,但是更方便的是使用 docker-compose 来进行容器编排,这样后面就可以通过一个配置文件和一些简单的命令来实现批量的启动和停止操作了。
这里的配置文件和 redis 配置文件的格式不同,这里使用的配置文件的格式是 YML 的格式。YML 格式跟 python 类似,使用缩进来表示成绩关系:
student: name:zhangsan id:1 age:18 score: chinese: 97 math:100这里我们使用两个 YML 配置文件来批量启动/停止,为什么用两个呢?因为需要保证 redis 节点的启动需要在哨兵节点之前启动,否则哨兵节点先启动的话,redis 节点没启动,那么哨兵就会认为 redis 节点挂了,虽然对于我们的正常流程没有什么影响,但是会生成错误日志,会对我们日常错误排查产生误导。虽然在一个 YML 配置文件中可以做到容器的先后启动,但是操作比较复杂。所以为了保证 redis 节点在哨兵之前启动,就三个 redis 节点使用一个 YML 配置文件,三个哨兵使用一个 YML 配置文件。
先创建出 redis-data 目录作为 redis-server 的工作目录,redis-sentinel 作为哨兵的工作目录:
root@iZ2ze5bzkbeuwwqowjzo27Z:~# mkdir redis-data root@iZ2ze5bzkbeuwwqowjzo27Z:~# mkdir redis-sentinel
然后在这两个工作目录中分别创建出 docker-compose.yml 文件,这个配置文件名是固定的,这也是前面为什么需要将 redis-server 和 哨兵 节点的工作目录分开。
然后向配置文件中添加内容,首先是 redis-data 配置文件中的内容:
version: '3.7' services: master: image: 'redis:6.0.16' container_name: redis-master restart: always command: redis-server --appendonly yes ports: - 6379:6379 slave1: image: 'redis:6.0.16' container_name: redis-slave1 restart: always command: redis-server --appendonly yes --slaveof redis-master 6379 ports: - 6380:6379 slave2: image: 'redis:6.0.16' container_name: redis-slave2 restart: always command: redis-server --appendonly yes --slaveof redis-master 6379 ports: - 6381:6379- version:版本号,这里我们默认使用3.7
- services:表示该配置文件需要启动的服务的名字,这里服务的名字是自定义的
- image:表示该容器是基于哪个镜像创建的
- container_name:容器的名称
- restart:表示如果当前容器意味异常情况挂掉了之后是否重启,always表示总是(手动停止容器不会自动重启)
- command:表示当前 redis 服务器启动的时候需要哪些选项
- ports:端口映射,因为docker容器就相当于一个轻量的虚拟机,既然是两台不同的主机,那么端口号之间是互不影响的,但是如果想要在容器外访问到容器内的端口号,那么就可以将容器内的端口号映射到宿主机的的端口
在从节点的 command 当中的 slaveof 选项中,本来是需要写主节点的 IP 和端口号,但是这里写的是主节点容器的名称,这是因为当容器启动的时候会自动分配一个 IP,然后具体的 IP 是啥我们也不能事先知道,所以就只能通过指定容器的名称,然后容器启动的时候就会进行类似的域名解析操作,将容器名改为对应的 IP。
配置完成 redis-data 的配置文件之后,我们可以使用 docker-compose up [-d]来启动容器,-d 选项表示后台启动:
root@iZ2ze5bzkbeuwwqowjzo27Z:~/redis-data# docker-compose up -d Starting redis-slave1 ... done Starting redis-master ... done Starting redis-slave2 ... done
在使用 docker-compose up 命令的时候可能会出现这样的问题:
这是因为我们的 docker 版本和 urllib 的版本不兼容,如果出现这样的问题,可以通过更新 docker 的版本或者使用 pip install 'urllib3





