《Redis》哨兵模式
文章目录
- 为什么要有哨兵模式呢?
- 哨兵自动恢复故障主节点
- 使用docker搭建分布式系统
- 查看哨兵节点工作
- 哨兵选举新的主节点的流程
- 总结
为什么要有哨兵模式呢?
主从复制的问题
Redis 的主从复制模式可以将主节点的数据改变同步给从节点,这样从节点就可以起到两个作⽤:
第⼀,作为主节点的⼀个备份,⼀旦主节点出了故障不可达的情况,从节点可以作为后备 “顶” 上
来,并且保证数据尽量不丢失(主从复制表现为最终⼀致性)。第⼆,从节点可以分担主节点上的读
压⼒,让主节点只承担写请求的处理,将所有的读请求负载均衡到各个从节点上。
但是主从复制模式并不是万能的,它同样遗留下以下⼏个问题:
- 主节点发⽣故障时,进⾏主备切换的过程是复杂的,需要完全的⼈⼯参与,导致故障恢复时间⽆法保障。
- 主节点可以将读压⼒分散出去,但写压⼒/存储压⼒是⽆法被分担的,还是受到单机的限制。
其中第⼀个问题是⾼可⽤问题,即 Redis 哨兵主要解决的问题。第⼆个问题是属于存储分布式的问题,后面Redis集群就是解决这个问题的。目前先解决第一个问题。
所以当主节点由于死机等问题,无法为客户端提供服务时,就需要通知大量的客户端,要更换主节点了。这对于已经部署好一定规模的客户端集群来说,是无法接受的,且更换主节点需要人工干预,耗时长,对效率大打折扣,所以,就引入了哨兵(Redis Sentinel)来解决这个问题。
哨兵机制是一个独立的redis-sentinel进程,不用来存储数据,而是用来监控redis的数据节点。
人工干预情况下:
依然有许多问题,如果引入了哨兵机制自动修复节点,会大大提高效率。
哨兵自动恢复故障主节点
单独的哨兵(redis sentinel)进程,提供了多个,这里以三个为例。(哨兵节点,最好是搞奇数个,最少是3个,一般情况下,都是搞三个。)
提供多个哨兵来监控主从节点的原因是防止单独的哨兵出现误判某个主节点挂了的情况。
还有如果单独一个哨兵节点,如果它自己本身都挂了,那就无法自动恢复故障的主节点了。
这些哨兵会对所有要监控的主从节点进行TCP的长连接,连接成功后,定期向节点发送心跳检测(这里的心跳检测是应用层实现的,不是tcp中的keep-alive,应用层实现的心跳检测一般是简单的ping,pong)
如果发现某一个主节点不回复心跳检测了,说明有可能挂了,此时多个哨兵讨论一致后,如果认为该主节点真的挂了,则会挑选出一个哨兵节点,由这个哨兵节点按照某些挑选规则,挑选出一个新的主节点。
挑选出新的主节点后,哨兵节点会自动控制该被选中的节点,执行slaveof no one,让他直接称为新的主节点,并控制其他从节点,修改slaveof到新的主节点上。
哨兵节点会自动通知所有客户端,告诉他们新的主节点是谁,后续客户端再进行写操作,就会针对新的主节点进行操作了。
使用docker搭建分布式系统
按理说,上面的6个节点是要部署在6台不同的服务器主机上的。
一方面为了高可用,不至于一台主机挂了,影响到其他主机。
一方面就是为了多使用其他主机的硬件资源,来提高效率。
虚拟机可以解决,但是非常吃硬件性能,一般的电脑是搞不起的。
所以使用docker,就能解决上述问题。
docker是一个轻量级虚拟机,既能起到像虚拟机一样的隔离环境作用,又不会吃太多硬件资源。
docker关键字:”容器“,容器就是一个轻量级的虚拟机。
操作步骤:
- 1.安装docker和docker-compose
ubuntu下:apt install docker, apt install docker-compose - 2.停止之前的redis服务器
service redis-server stop ,或者ps axu | grep redis,查看redis服务器进程的pid,kill -9 pid 即可。 - 3.使用docker获取到redis的镜像
简单解释一下docker的镜像和容器的关系。
镜像相当于可执行程序,容器相当于进程。
要启动一个进程,那就要启动一个可执行程序,才能成功启动进程。
换句话说,要创建一个容器,那就得有描述该容器的一个模板,根据模板刻画一个容器出来,才能使用。所以获取redis镜像,就相当于获取相关的容器的可执行程序。
镜像可以自己构建,也可以拿别人构建好的(官方给的docker hub,类似github,有大量开源的镜像)
拉取镜像命令
docker pull redis(docker pull默认就是从配置好的docker hub中拉取的)
检查是否安装成功:
docker images
如果看到有redis的镜像,则说明安装成功了。
接下来则使用一些配置文件(yml)格式,来实现使用简单的命令控制多个redis节点,这些节点在docker就是一个个容器,一个节点就使用一个容器。
简单理解yml格式:
yml格式相对于xml格式来说,xml格式一般都是以标签的形式成对出现的。
<student><id>1</id><name>张三</name>
</student>
这种格式比较啰嗦,且空间大。
后来就有了json:
{id: 1,name: ”张三“
}
json格式写起来方便,还减少了空间,json以{}表示层级结构的。
而对于yml格式来说,与json格式有些相似之处:
student:id: 1,name: 张三
yml是以缩进格式来表示层级结构的。
下面创建6个容器,三个是作为redis的数据节点(一主两从)
三个是作为哨兵节点。
先创建一个目录
mkdir -p redis/
cd redis/
mkdir -p redis-data/
mkdir -p redis-setinel/
这两个目录一个是放redis的数据节点,一个是放哨兵节点的。
cd redis-data/
vim docker-compose.yml (注意:配置文件的名字是固定的,不要改)
(注意缩进表示层级)
version: '3.7' # 版本号
services: # services中的master,slave1是自己设定的名字master:image: 'redis' # 要使用的镜像名container_name: redis-master # 容器名字restart: always # 一些配置command: redis-server --appendonly yes ports: #这里重点说明- 6379:6379slave1:image: 'redis'container_name: redis-slave1restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379#这里可以直接通过容器名字,直接被docker进行类似域名解析的操作,获取到redis服务器的ip了ports:- 6380:6379slave2:image: 'redis'container_name: redis-slave2restart: alwayscommand: redis-server --appendonly yes --slaveof redis-master 6379ports:- 6381:6379
port重点说明,docker 中的容器就是一个轻量级的虚拟机,可以隔离环境。
容器内的端口号和容器外的端口好可以相同的。
比如容器内可以使用6379,容器外也可以使用6379。
彼此不冲突。
但是如果想在容器外能够访问到容器里面的端口号,
就可以把容器内部的端口号映射成宿主机的端口号。
ports:
- 6380:6379
第一个port是宿主机的端口号,第二个port是容器内的端口号
相当于容器外(宿主机)映射后的端口号就是第一个,第二个就是容器内部自己的端口号
后续想要访问容器内的某个端口号,就可以直接通过访问宿主机这个映射的端口号,就等于访问容器内的那个端口号了。
但是也要注意,映射出去的端口号也不要再使用,防止冲突。
启动刚才配置的所有容器
docker-compose up -d
通过docker-compose logs就能看到日志信息。
netstat -anp | grep 端口号,通过grep刚才在配置文件写好的端口号:6379,6380,6381,就能看到三个redis节点已经起来了。
下面要创建三个redis哨兵节点的容器。
cd /redis/redis-sentinel/
vim docker-compose.yml文件
version: '3.7'
services:sentinel1:image: 'redis:5.0.9'container_name: redis-sentinel-1restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel1.conf:/etc/redis/sentinel.confports:- 26379:26379sentinel2:image: 'redis:5.0.9'container_name: redis-sentinel-2restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel2.conf:/etc/redis/sentinel.confports:- 26380:26379sentinel3:image: 'redis:5.0.9'container_name: redis-sentinel-3restart: alwayscommand: redis-sentinel /etc/redis/sentinel.confvolumes:- ./sentinel3.conf:/etc/redis/sentinel.confports:- 26381:26379
networks: default:external:name: redis-data_default
解释networks:指定当前所处的网络是redis-
data_default。
接下来创建三个redis哨兵节点的配置文件。
sentinel1.conf,sentinel2.conf,sentinel3.conf。
都放在redis-sentinel/目录下。
.conf配置文件信息如下
bind 0.0.0.0
port 26379
sentinel monitor redis-master redis-master 6379 2
sentinel down-after-milliseconds redis-master 1000
docker-compose up -d
创建三个哨兵节点
docker network ls
就能看到,只有一个局域网redis-data,而不是有redis-data又有redis-sentinel,这是因为.yml文件的network的作用。
查看哨兵节点工作
接下来就可以查看哨兵节点如何工作了。
docker ps -a,查看工作中的容器,就有三个redis的哨兵节点,三个redis主从节点。
接下来手动挂掉主节点
docker stop + 主节点名字(这里是redis-server)
此时主节点挂了,此时哨兵节点已经开始工作了
docker-compose logs ,查看日志
可以看到哨兵已经选出了新的主节点了。所以故障恢复完成。
哨兵选举新的主节点的流程
细节都在图中了,看图