目录
1、为什么要引入哨兵
1.1、主从复制的缺陷
Redis的主节点如果挂了(在公司中,一般会有监控程序来监控各个节点,如果某节点挂了,就会有报警机制),需要人工干预才能恢复。恢复步骤如下:
- 检查是否能够快速解决问题,重启主节点
- 短时间内查不出问题所在,或者知道问题但是短时间内无法修改,则需要人工手动执行命令,将其中一个从节点晋升为主节点---->原本的主节点修复后,将其按照从节点放置
上述内,但凡是人为的操作,就可能存在操作有误或者是,报警没有及时收到去解决问题~
1.2、引入哨兵解决主从复制的缺陷
1.2.1、哨兵——名词解释
- 主节点:逻辑结构上属于Redis主服务;物理结构上指的是一个独立的redis-server进程
- 从节点:逻辑结构上属于Redis从服务;物理结构上指的是一个独立的redis-server进程
- Redis数据节点:逻辑结构上包括主从节点;物理结构上指的是主从节点的进程
- 哨兵节点:逻辑结构上指的是监控Redis数据节点的节点;物理结构上指的是一个独立的redis-sentinel进程
- 哨兵节点集合:逻辑上指的是若干个哨兵节点的抽象组合;物理结构上指的是若干个redis-sentinel进程
- Redis哨兵:物理结构上指的是Redis提供的高可用的方案;物理结构上指的是哨兵节点集合和Redis主从节点
- 应用方:逻辑结构上应用方泛指客户端;物理逻辑上指的是一个或多个连接Redis的进程
1.2.2、哨兵自动恢复主节点故障
我们根据下面的一个Redis Sentinel架构示例来看:
说明:
- 上述提供了多个redis sentinel进程。并且这三个哨兵进程都会监控现有的redis master和slave
- 所谓监控,其实就是进程之间建立tcp长连接,通过这样的长连接,定期发送心跳包ping-pong
- 通过监控机制,就可以及时发现某个主机是否挂了
- 如果一个哨兵发现主节点挂了,这时其他哨兵就会过来确认是否真的挂了【降低误判概率】
- 如果确认主节点挂了,这些哨兵就会推举出一个哨兵leader,有这个leader来负责从现有的从节点中,挑选一个作为新的主节点
- 挑选出主节点后,哨兵节点就会自动控制这个被选中的节点,执行slaveof no one,并且控制其他从节点,修改slaveof到新的主节点上
- 修改后,哨兵节点就会自动通知客户端程序,告知新的主节点是谁,并且后续的客户端再进行写操作时,就会针对新的主节点进行操作了
- 总结哨兵功能:监控 + 自动的故障转移 + 通知
为什么上述不是使用一个哨兵节点:
- 一个哨兵,如果哨兵这个节点挂了,后续redis主节点挂了,就无法进行自动恢复过程了
- 一个哨兵,出现误判概率高~
所以通常情况下,哨兵节点最好是奇数个,最少3个~
2、基于docker的安装部署
2.1、为什么要在docker上安装部署?
原因一:
首先呢,根据我们上一篇文章,学习的是主从复制,在那边是在云服务器上,启动三个redis服务器来模拟在3个主机上有三个redis服务器,以此实现了redis主从节点,在这当中,我们要复制三个redis配置文件,并且要在三个节点中修改其端口号、配置文件、数据文件等信息,其实在哨兵这里,我们同样,也可以这样实现~
但是在实际工作中,把各个节点放在一台服务器上,是没有意义的;话说回来,我们这里只是为了学习和看到效果,在一台服务器上也可以,但是步骤繁琐,比实际操作要繁琐很多,那使用docker可以有效解决,节省时间,何乐而不为呢~
原因二:
docker类似于是一个“轻量级”的虚拟机(虚拟机大家应该都知道的,就是通过软件在电脑上模拟出另外的一些硬件,简单来说就是构造了另一个虚拟的电脑。那就会有小伙伴说,为什么不使用虚拟机呢?因为虚拟机比较吃配置,一般的小服务器都支撑不起来~)。而docker可以起到像虚拟机这样的隔离效果,但是又没有吃很多的硬件资源,即便是配置比较拉垮(像本博主的这种)的服务器,也能构造出好几个这样的虚拟环境~
2.2、简单介绍一下docker
docker中有一个概念--->“容器”。我们这里只是简单介绍,就不具体深挖了。简单说,容器我们可以理解这里的容器可以看做是一个轻量级的虚拟机。
docker中的“镜像”又怎么理解呢?我们可以简单理解为镜像就是一个“可执行程序”,这个“可执行程序”可以是自己构建,也可以是直接使用别人构建好的~
docker中“容器”和“镜像”结合来理解:“镜像”就是一个“可执行程序”,“容器”就是一个“进程”,并且一个“可执行程序”可以运行多个“进程”。例如我们我们一个浏览器是一个可执行程序,打开一个页面是一个进程,可同时打开多个页面~这种比喻不是很恰当,因为一个容器内部是一个自己的小天地,可以理解为,一个容器就是一个主机~
下面开始编排各个节点,如果有小伙伴的docker没有安装,自行百度哈~
2.3、编排redis主从节点
2.3.1、编排前:
在编排节点前,并且安装了docker的伙伴,准备以下几点:
- 看一下有没有安装docker-compose,如果没有安装,命令:yum install docker-compose
- 停止之前的redis-server
- 使用docker获取redis镜像:docker pull redis:5.0.9 【这里的pull,类似于git中的pull,就是使用docker从中央仓库中来拉取镜像->默认是从docker hub中拉取】---->拉取后,这个镜像中就有一个精简的Linux操作系统,并且上面有安装指定的Redis,只要基于这个镜像创建一个容器跑起来,此时Redis服务器就搭建好了~
使用命令:docker images
以上就算是成功了~
2.3.2、编排操作:
我们这里,为了避免麻烦,将Redis数据节点的编排和redis-sentinel节点编排分开了~
Redis数据编排这里:我们是准备创建了三个容器,作为Redis的数据节点——一个主节点,两个从节点~
第一步:编写docker-compose.yml
这样两个目录其实就是为了把数据节点和哨兵节点分隔开~
将以下内容复制到这个yml文件中:
version: '3.3'
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
这里需要注意,yml文件对格式要求很严格,缩进不对的,后续会出现问题,所以大家复制后,仔细检查一下缩进是否正确~
说明:
- 为什么slaveof后主节点的ip使用主节点的容器名字表示而不是具体ip?原因:在容器启动后,分配的ip是动态的(也可以在配置中指定静态ip),所以没办法确定,而容器名就类似于域名,docker自动进行域名解析,就可以的得到对应的ip
- port那里写宿主机端口号和容器内部端口号是什么意思?上述我们提到过,可以把一个容器看做是一个主机,那么容器内的6379端口和容器2的6379端口号是互不影响的~ 而此时我们希望在容器外范文容器内部的端口,需要进行端口号映射,把容器内的端口号映射到宿主机上,后续访问宿主机的这个端口就相当于是访问对应容器的对应端口号了
第二步:启动容器
- 命令:docker-compose up -d
- -d:指的是后台运行~
- 如果发现启动后前面的配置有误,使用命令:docker-compose down -->停止并删除当前目录下创建好的容器~
- 查看是否启动:
- 检查宿主机的端口状态:
- 进入各个端口对应的redis服务器:
- 查看运行日志命令:docker-compose logs
2.4、编排redis-sentinel节点
redis哨兵节点是单独的redis服务器进程
2.4.1、编写compose.yml文件
复制以下内容到文件中:
version: '3.3'
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
networks:
default:
external:
name: redis-data_default
同样的问题,要注意缩进~
说明:
- 为什么要进行配置文件的映射?因为容器中原本是默认有redis数据节点的配置文件,而没有哨兵节点的配置文件,所以需要我们自行配置,我们则是采用文件映射的方式去配置,方便快捷
- 为什么每个哨兵节点的配置文件都不一样?因为我们在初始情况下,各个哨兵节点的配置文件内容可以是一样的,但是当容器启动时,会自动进行修改各自的配置文件,不能相互混淆了,所以每个映射的文件都是不同的~
- 为什么有下面network巴拉巴拉的,局域网巴拉巴拉的?因为这里涉及到一个docker的注意事项:我们在使用docker-compose来启动多个容器时,这多个容器是处于同一个局域网下的,所以这多个容器间可以相互访问,否则就不能相互访问。还是不明白为什么?那是因为你还不知道哨兵的配置文件有什么东西(下面会有配置文件的说明),配置文件中会用到我们上述已经启动过的主节点的一些信息,而主节点和哨兵节点不是在一起启动的,就不在同一个局域网下,所以无法访问到主节点的信息。因此我们这在这里在进行设置,将这些哨兵节点放在指定的redis数据节点下的局域网下启动~
2.4.2、如何查看redis数据节点的局域网名:
命令:docker network ls
这里其实也可以把数据节点和哨兵节点放在一起启动,但配置起来会稍微麻烦一些~
2.4.3、哨兵的配置文件:
创建配置文件目录:
将以下内容复制进去:
bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000
说明:
我们来复制其他两个哨兵节点的配置文件~
2.4.4、启动哨兵节点:
- 命令:docker-compose up -d
- 查看是否启动:
- 检查宿主机的端口状态:
- 查看日志文件:docker-compose logs
2.4.5、再次查看哨兵节点的配置文件
以上除了红框以外的,都是自动修改的,并且红框中的ip也自动替换好啦~
3、哨兵节点重新选举主节点的流程【面试重点】
3.1、主动杀死redis主节点
能看上图中的主节点已经挂了,进不去了~
3.2、检查主节点是否被替换
3.3、哨兵重新选取主节点的流程
具体流程我们来结合根据日志看~
这日志文件中,我们会看到有一个哨兵的日志会明显多余另外的哨兵日志,此时说明,这个哨兵是被选举出作为leader,来负责选一个从节点来作为新主节点~
下面我就根据这个日记文件最多的这个来说~
下面开始正式的重新选取的流程:
3.3.1、主观下线
哨兵节点通过心跳包,判定redis服务器是否正常工作。如果心跳包没有如约而至,就说明redis服务器挂了~
但是这里不能排除是因为网络波动的影响,因此只能单方面的认为这个redis节点挂了,也就是主观下线~
3.3.2、客观下线
多个哨兵都认为是主节点挂了(认为主节点挂了的哨兵个数达到法定票数),则哨兵们就认为这个主节点时 客观下线~
如果说出现严重的网络波动,导致多数哨兵都认为主节点挂了,而出现了误判。那这种情况下,恐怕是客户端也连不上redis主节点了~所以说,“挂了”并一定是进程崩了,只要是无法正常访问,都可以视为挂了~
3.3.3、选取leader节点
- 当第n号哨兵第一个发现当前是客观下线后,就会立即给自己投一票(选自己为leader),并且告诉其他的哨兵,我来负责。因为其他哨兵晚发现,同时又看到n号哨兵愿意负责这个事情,就会立即投票给他~【如果某个节点的票数超过哨兵总数一半,选举完成,所以哨兵个数最好为奇数个,方便投票;谁先发现是客观下线,就是看谁的网络延时更小;n号告诉其他哨兵,他来负责,就是在拉票,如果多个哨兵在拉票,就会投给最先到达的】
- 其他哨兵陆续投票
- n号哨兵成为leader
3.3.4、选取从节点作为新的主节点
由leader来挑选一个从节点作为新的主节点~
挑选的从节点规则如下:
- 优先级:每个redis数据节点都会在配置文件中,有一个优先级的设置,slave-priority---优先级高的从节点就会胜出。如果没有设置默认优先级就是一样的
- offset:offset指的就是从节点这边同步主节点的进度,数值越大,说明同步的数据越多,则谁胜出
- run id:每个redis节点启动就会随机生成一串数字,谁大谁胜出【不会重复】
3.3.5、执行命令slave no one
把新的主节点指定后,leader会控制这个从节点,执行slave no one,成为master;控制其他节点执行slave of {ip} {port},让他们以新的主节点作为master
3.3.6、原本的主节点被修复
当原本的主节点修复后,再次启动该节点,会自动补成从节点
4、哨兵的相关注意事项
- 哨兵节点不能只有一个,否则哨兵节点挂了,也会影响系统可用性
- 哨兵节点最好是奇数个,方便选举,得票更容易超过半数
- 哨兵节点不负责存储数据,仍然是redis主从节点负责存储
- 哨兵 + 主从 复制解决的问题:“提高可用性”,不能解决“数据极端情况下写丢失”的问题
- 哨兵 + 主从复制不能提高数据的存储容量,当我们需要存的数据接近或超过机器的物理内存时,就难以胜任,需要使用集群解决~
好啦,下期见,集群的相关知识~