引言
主节点:代表一个独立的redis-server进程
从节点:一个独立的redis-server进程
实际开发中,对于服务器后端开发,监控程序,是十分重要的,服务器7*24小时运行
长期运行,总会有意外,什么时候坏,说不好,也不能全靠人盯着。
于是大佬想了一个办法,用一个程序来盯着服务器运行状态-监控程序+报警程序(发现服务器运行出现状态异常,给程序员报警,说这个服务器程序挂了,出现问题了)
如何解救:
1.先看主节点能不能抢救,好不好抢救
2.主节点这边什么原因挂的,不好定位,或者原因知道,但是短时间难以解决,就需要挑一个节点,设置为新的主节点
a.把选中的从节点通过slaveof no one,自立山头
b.把其他的从节点,修改slaveof的主节点ip port,连上新的主节点
c.告知客户端(修改客户端的配置),让客户端能够连接新的主节点,用来完成修改数据的操作
当之前的主节点修好之后,可以作为新的从节点,挂到这组机器中~
但是人工干预,不说是繁琐,但是也很烦人。程序员恢复操作也不是很快。
哨兵的初心
1.借助上述的监控机制,就可以及时发现某个主机是否挂了。此时,一个哨兵节点发现主节点挂了,还不够,需要多个哨兵节点来共同认同这件事情,主要是防止出现误判
2.主节点确实挂了,哨兵节点中推出一个leader,由这个leader复制从现有的从节点中,挑选一个作为新的主节点
3.挑选出新的主节点之后,哨兵节点,就会自动控制该被选中的节点,执行slaveof no one 并且控制其他从节点,修改slaveof到新的主节点上~
4.哨兵节点会自动通知客户端程序,告诉新的主节点是谁,后续就针对这个新的主节点进行操作。
Redis哨兵核心功能
1.监控
2.自动的故障转移
3.通知
1.注意redis哨兵节点,有1个也是可以的,但是一个不如多个(最好奇数个,方便后续选举),哨兵节点有一个,它自身也是容易出现问题的,万一这个哨兵挂了,不久无法自动的进行恢复过程了
2.出现误判的概率比较高,只有一个哨兵节点,出现上述问题之后,影响就比较大~
基本的原则:在分布式系统中,应该避免使用单点 ->冗余
如何节点的搭建-docker是没意义的,但是没钱
前言:把上述节点放到一个服务器上是没意义的,但是没钱
类似于最开始进行主从结构配置的方式,比较繁琐,也会和在不同主机上部署,存在较大差异。
什么是docker
虚拟机通过软件,在电脑上模拟出另外一些硬件(构造了另一个虚拟的电脑,虚拟机的问题就是比较吃配置,对于云服务器来说,亚历山大) docker可以认为是更轻量级的虚拟机(起到了虚拟机这样的隔离还击,但是又没有吃很多硬件资源),即使配置比较辣椒的,也能构造出这样的虚拟环境
1.先去安装docker和docker-compose
2.停止之前的redis服务器
3.使用docker获取到redis镜像
像和容器-类似于可执行程序和进程的关系
镜像可以自己构建,也可以拿别人已经构造好的
docker pull redis:5.0.9
如同git pull使用git中央仓库拉取代码,docker pull使用docker从中央仓库(默认是docker hub)来拉取镜像
拉去到的镜像,里面包含一个精简的Linux系统,并且上面安装了redis,只要直接给予这个镜像创建一个容器跑起来,此时redis服务器就搭建好了。
查看docker内部的镜像
基于docker来搭建redis哨兵环境了
docker-compose来进行容器的编排->此处涉及到多个redis server也有多个redis哨兵节点~,每一个redis server或者每一个redis哨兵节点都是作为一个单独容器了
什么叫容器编排:通过一个配置文件,把具体要创建哪些容器,每个容器运行的各种参数,描述清楚,后面通过一个简单的命令,就能够批量的启动/停止这些容器了。
使用yml格式作为配置文件。
1.创建三个容器,作为redis的数据节点(一个主,两个从) yml
2.创建三个容器,作为redis的哨兵节点 yml
其实也可以用一个yml,直接启动6个容器,如果6个同时启动,可能哨兵先启动,数据节点后完成,哨兵就会可能认为数据节点挂了,虽然对大局不影响,但是会影响观察执行日志的过程~
配置名字是固定的
进行内部的配置
services的名字是我们自己设定的
image:当前容器是根据哪个镜像进行创建的
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 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ "docker-compose.yml" 25L, 572C 18,11 All
docker容器可以理解成是一个轻量的虚拟机,在这个容器,端口号和外面宿主端口号是两个体系,如果容器外使用了5050端口,内部仍可以使用5050,二者没有冲突
三个容器,容器内部的端口号都是自成一派,容器1和2的6379没有冲突,容器外想去访问容器内部的端口则需要进行端口映射,后续访问宿主机这个端口,就相当于访问对应容器的对应端口了,站在宿主的角度,访问上述几个端口,也不知道是宿主机上的服务还是容器内部的服务,只需要正常去用即可。
上面这块不必写主节点ip,直接写主节点的容器名,容器启动之后,被分配的ip是啥也不知道(有办法配置静态IP)容器名类似于域名,docker自动进行域名解析,就得到对应的ip
配置之后使用这个命令docker-compose up -d
配置哨兵节点
docker的核心功能,能够进行端口的映射,容器内使用啥端口,映射出去后,还是要确保端口不能重复的
version: '3.7' services: sentinel1: image: 'redis:5.0.9' container_name: redis-sentinel-1 restart: always command: redis-sentinel1 /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 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ "docker-compose.yml" 29L, 757C 23,35 All
redis哨兵节点是单独的redis服务器进程
redis-master :告诉哨兵节点,让他监视哪一个redis服务器
6379:这里其实是ip,但是使用docker,docker自动进行域名解析
2:法定票数
down-after-milliseconds:心跳包的超时时间
bind 0.0.0.0 port 26379 sentinel monitor redis-master redis-master 6379 2 sentinel down-after-milliseconds redis-master 1000
启动后,我们查看docker的日志,牛魔的一堆错误
此处,这个哨兵节点,不认识redis-master,redis-master相当于一个域名,docker会进行域名解析,docker-compose一下启动了N个容器,此时N个容器都处在同一个局域网中,可以使这N个容器之间可以相互访问,三个redis-server节点,是一个局域网,三个哨兵节点,是另一个局域网
默认情况下,这两个网络并不互通
解决方案:可以使用docker-compose把此处两组服务给放到同一个局域网中,docker network ls列出当前docker中的局域网,docker-compose文件所在的目录名字
此处先启动了三个redis server节点,就相当于创建了第一个局域网,在启动后面三个哨兵节点,就直接让这三个节点加入到上面的局域网中,而不是创建新的局域网!
(这里的关键是必须要是上面那个局域网,即data那个局域网)
此时就没有什么太大的问题了。
通过上述的操作,就完成了此处的配置~
是否可以把六个容器,都写到同一个ym配置中,一次都启动,不就直接保证互通问题了吗?
如果用这种方案,docker-compose启动容器的顺序不确定,无法保证redis-server一定在哨兵之前启动的,分成两组来启动,就可以保证上述顺序。观察到的日志,比较可控。
我们可以观察到有好多东西,都和我们第一次写的时候不一样,哨兵节点启动之后,自动进行修改的
哨兵存在的意义:
能够在redis主从结构出现问题的时候,此时哨兵节点能够自动帮助我们重新选出一个主节点,来代替之前挂了的节点,保证整个redis仍是可用的状态。
手动干掉主节点,(看最后一个Exit那个)主节点挂了,哨兵节点开始工作,前半部分是哨兵刚启动的时候的日志,redis-master挂了
我们来查看此时的日志,sdown主观线下:本哨兵节点,认为该主节点挂了
odown客观下线:好几个哨兵都认为该节点挂了,达成了一致(法定票数,此时主节点挂了这件事就被定下了)
此时就需要哨兵节点选出一个从节点,作为新的主节点,此处就需要选拔出一个新的主节点
此时就能够看到它挂了。
我们可以看到此时的6381是作为主节点了,而6380仍作为从节点
就算我们把原先的主节点恢复,他也会变成从节点,挂到主节点下面
以上就可以保证,原有的节点挂了,可以保证系统仍正常工作
哨兵重新选取主节点的流程
1.主观下线
哨兵通过心跳包,判定redis服务器是否正常工作,如果心跳包没有如约而至,就说明redis服务器挂了,此时还不能排除网络波动的影响,因此就只能单方面认为redis这个节点挂了
2.客观下线
多个哨兵都认为主节点挂了(认为挂了的哨兵节点数目达到了法定票数)哨兵们就认为这个主节点是客观下线(比如出现很严重的网络波动,所有哨兵都联系不上redis主节点,但是这种情况,基本客户端也连接不上redis主节点,此时这个主节点也无法正常工作了
挂了不一定是进程崩了,只要无法正常访问,都可以视为是挂了
3.要让多个哨兵节点,选出一个leader,由这个leader负责选一个从节点作为新的主节点
投票过程看,网络延迟谁更小
4.leader选举完毕,leader就需要挑选一个从节点,作为新的主节点
1)优先级:每个redis数据节点,都会在配置文件中,有一个优先级的设置.slave-priority优先级高的从节点,就会胜出
2)offset 最大,就胜出 offset从节点从主节点这边同步数据的进度,数值越大,说明从节点的数据和主节点越接近
3)随缘
把新的主节点指定好了之后,执行slave no one,成为master,再控制其他节点,执行slave of,让这些其他节点,以新的master作为主节点了。
小结:
使用哨兵注意事项
哨兵节点不能只有一个,否则哨兵节点挂了也会影响系统可用性
哨兵节点最好奇数个,方便选举leader,得票容易超过半数
哨兵节点不负责存储数据,仍然是redis主从节点负责存储
哨兵节点+主从复制解决的问题是"提高可用性",不能解决数据极端情况下写丢失