走进Redis:哨兵集群(哨兵模式redis集群)
mhr18 2024-11-12 11:24 13 浏览 0 评论
为什么需要哨兵
在 Redis 的主从库模式中,如果从库发生了故障,用户的操作是可以继续进行的,因为写操作是只在主库中进行的。那么,如果主库发生了故障,用户的操作将会收到影响。这时候可能会需要选择一个从库在作为主库继续服务用户的操作。Redis 提供的哨兵机制就是解决主从库模式的 Redis 服务可用性问题的。
故障转移的基本流程
哨兵发现主库下线并选出新主库的流程称为故障转移,这个过程需要解决三个问题:
- 主库真的挂了吗?(监控)
- 该选择那个从库作为主库?(选主)
- 怎么把新主库的相关信息通知给从库和客户端呢?(通知)
监控
哨兵在运行过程中周期性的给所有主从库发送 PING 命令,以此检测它们是否正常运行。如果某个实例对 PING 命令的没有在 down-after-milliseconds 应答,那么,哨兵会把它标记为“ 主观下线 ”。
哨兵不会对主观下线的从库做额外的处理,如果是主库主观下线,那么哨兵会进行后续的选主和通知操作,这些操作会有额外的计算和通信开销。为了减少误判,哨兵通常会采用集群部署。当一个哨兵将 master 标记为主观下线后,会和其它哨兵实例通过命令 SENTINEL is-master-down-by-addr 交流,如果有大于 quorum 个哨兵确认 master 已下线,则该 master 会被标记为” 客观下线” ;否则,会重新将 master 标记为上线状态。
:bulb: quorum 通过 sentinel.conf 配置得到,和哨兵集群中实例的数量有关。例如,若共有 3 个实例,则该值可设置为 2 ,最好将该值设置为 $N/2+1$ 。该值越小,判断 master 客观下线的条件越宽松;反之则判断 master 客观下线的条件越严格。通常哨兵集群中实例的数量为奇数,避免出现应答下线和未下线数量相同的情况。
选主
选新主库的过程大致可以分为以下几个步骤:
哨兵 Leader 选举
哨兵 Leader 是本次故障转移的执行者,每个哨兵都有机会成为 Leader。具体流程如下:
- 当哨兵将 master 节点标记为客观下线后,会将当前纪元(epoch,该值类似 raft 协议的 term 值)加一,表示开始一次新的 leader 选举。
- 首先会给自己投一票,然后会再次发送 is-master-down-by-addr 给其它哨兵。这个命令的使用方式如下: sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid> 。这里主要看 runid,确认主节点是否客观下线时,该值为 *;开始参选 Leader 时,传的参数为本节点的 runid。
- 收到命令的哨兵,如果没有同意过其他节点的 sentinel is-master-down-by-addr 命令,将同意该请求,否则拒绝。并且同意过其它节点后,该节点也不会发起投票。
- 如果该哨兵发现自己的票数已经大于等于 max(quorum, num(sentinels)/2+1) ,那么它将成为领导者。
- 如果此过程没有选举出领导者,将进入下一次选举。选举超时时间可以查看配置 failover-timeout 。
筛选
- 首先会判断从库当前的状态,过滤掉当前主观下线以及断线的节点;
- 5 秒内没有回复过哨兵节点 PING 请求的节点;
- 与主节点断连次数超过 10 次的节点。是否断连是根据配置项 down-after-milliseconds 来判断的,主从节点 down-after-milliseconds 毫秒内都没有连接上,则会被记为一次断连。
打分
- 通过配置项 slave-priority 来给不同的从库设置不同的优先级 。可以使用命令 info Replication 来查看该配置。如果有一个从库的优先级最高,那么该从库会直接选为新主库;否则,将会进行第二轮打分。
- 与旧主库同步程度最接近的从库得分高 。在主从同步中提到过,从库会用 slave_repl_offset 来记录当前从 master 的复制进度,该配置通过 info Replication 可以查看。哨兵会选出复制进度值最大的从库作为新的主库,如果多个从库复制进度并列第一,那么需要进行第三轮打分。
- ID 号最小的从库得分高 。最后,哨兵会查看从库的 runId ,将 runId 最小的从库作为新主库。runId 通过命令 info Server 可以查看。
通知
当选出新主库之后,哨兵有三个角色需要通知:
- 告诉新主库它已经称为了新主库 。哨兵会向目标库发送命令 slaveof no one ,收到命令后,目标库会将自己的角色( role )提升为 master 。
- 告诉其它从库新主库的地址 。哨兵会向其它从库发送 slaveof host port 来告诉从库新主库的地址,从库会执行 replicaof 命令开始从新主库同步。
- 通知客户端主库变化。 当新主库切换完成后,哨兵会在频道 +switch-master 中发送消息,通知外部客户端新主库地址。
哨兵集群
上面讨论主从切换的时候有提到哨兵集群来减少主库客观下线误判的可能性。哨兵监控一个 master 节点是通过下面这个命令来完成的:
sentinel monitor <master-name> <ip> <redis-port> <quorum>
这个命令中并没有指定其它哨兵的地址信息,那么哨兵是如何组成一个集群的呢?
基于 pub/sub 机制的哨兵集群
哨兵成功和主节点建立连接之后,会在主节点上创建一个名为 “ sentinel :hello” 的频道,然后会将自己的地址端口等信息发布到该频道,其它哨兵就可以从这个频道获取监控同一个主节点的哨兵信息,互相建立网络连接,形成一个集群。
:bulb: 我们可以用 redis-cli 连接上主节点,然后用命令 psubscribe * 监听主节点上的所有频道,会看到哨兵不断在 __sentienl__:hello 频道发送自己的信息。
获取从库信息
redis 主库会保存从库的信息,哨兵会向主库发送 INFO 命令来获取从库列表。哨兵就可以根据从库列表的地址信息和每个从库建立连接,然后监控从库的状态。
哨兵获取从库信息主要是 INFO 命令查看主库的 replication 信息,典型的一个 replication 信息如下所示:
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.26.0.3,port=6379,state=online,offset=217874,lag=0
slave1:ip=172.26.0.2,port=6379,state=online,offset=217874,lag=0
master_failover_state:no-failover
master_replid:51567b12a9c1ba1d82846a8fb8fd84404b60eaf8
master_replid2:0baa276d98298739b2e0755640fd5b50d2828b26
master_repl_offset:217874
second_repl_offset:17993
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:429
repl_backlog_histlen:217446
从信息里可以看到主库的 role 为 master ,已连接的从库数量(connected_slaves)为 2,然后 slave0 和 slave1 就是从库的信息。
哨兵会定期给主库和从库发送 PING 命令检测网络状态,如果超时未应答就会标记为主观下线,如果主观下线的是主库,就会开启故障转移流程。
客户端访问 redis-server
客户端如何访问哨兵集群监控的 redis-server 呢?主要有以下几个步骤:
- 连接哨兵集群 。客户端初始化时,需要提供哨兵的地址,客户端会连接到第一个可用的哨兵地址。
- 连接主库 。客户端给哨兵发送 SENTINEL get-master-addr-by-name <master-name> 获取主库地址,然后和主库建立连接。为了确认连接的确实是主库,客户端还需要发送 info replication 命令来查看 role 是否是 master,如果不是的话就要从第一步重新开始。
- 连接从库 。客户端给哨兵发送 SENTINEL replicas <master-name> 来获取从库信息。相应的,客户端也可以通过 info 命令来确认目标的角色。
- 监听主库迁移 。哨兵通过 pub/sub 来通知客户端集群中的事件。哨兵提供的订阅频道很多,具体可以查看 https://redis.io/docs/manual/sentinel/#pubsub-messages 。客户端使用命令 psubscribe * 来订阅所有的频道,来了解主从切换的进度。当频道 switch-master 有新消息时,表示新主库已经切换完成。
实验
可以使用以下 docker-compose 来简单模拟故障迁移的实验:
version: "3"
services:
redis-master:
image: redis:7
ports:
- "16379:6379"
container_name: "redis-master"
command: redis-server
networks:
- sentinel-network
redis-slave-1:
image: redis:7
ports:
- "6380:6379"
container_name: "redis-slave-1"
command: redis-server --replicaof redis-master 6379
depends_on:
- redis-master
networks:
- sentinel-network
redis-slave-2:
image: redis:7
ports:
- "6381:6379"
container_name: "redis-slave-2"
command: redis-server --replicaof redis-master 6379
depends_on:
- redis-master
networks:
- sentinel-network
redis-sentinel:
image: bitnami/redis-sentinel:latest
environment:
- REDIS_MASTER_HOST=redis-master
- REDIS_SENTINEL_QUORUM=2
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=10000
depends_on:
- redis-master
- redis-slave-1
ports:
- '26379-26381:26379'
networks:
- sentinel-network
networks:
sentinel-network:
使用命令 docker-compose up --scale redis-sentinel=3 来启动 docker-compose。启动之后会打出如下的日志:
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 * Sentinel new configuration saved on disk
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 # Sentinel ID is 787487fa6116b997caa0a44b011793b58e265a54
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.825 # +monitor master mymaster 172.27.0.2 6379 quorum 2
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.827 * +slave slave 172.27.0.3:6379 172.27.0.3 6379 @ mymaster 172.27.0.2 6379
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.840 * Sentinel new configuration saved on disk
redis-sentinel_1 | 1:X 11 Aug 2022 03:59:21.840 * +slave slave 172.27.0.4:6379 172.27.0.4 6379 @ mymaster 172.27.0.2 6379
日志表示这样一个流程:哨兵初始化完成 ? 监控主库 ? 监控从库。
此时,如果连接上主库,然后订阅 __sentinel__:hello 频道,可以看到如下的消息:
集群内的哨兵都在往 __sentinel__:hello 发送自己的服务信息。
可以使用命令 docker stop redis-master 来模拟主库下线的情况,在执行这个命令之前可以先连到哨兵节点 redis-cli -p 26379 ,然后用命令 psubscribe * 来订阅哨兵的频道,这样模拟主库下线时就能看到哨兵通过频道通知客户端的消息了:
结语
Redis 哨兵的相关原理暂时告一段落,欢迎大家交流。
相关推荐
- Docker集群管理之Docker Compose
-
前言:在上一篇《Docker集群管理之DockerMachine》中,我们通过源码分析了解了DockerMachine的工作原理,使用者可以通过DockerMachine的一条命令在任意支持的平...
- 使用Dockerfile build镜像
-
Docker映像可以看作是Docker容器的压缩包,包含了应用程序以及运行应用程序所需的依赖,容器是映像的运行时实例。一般构建镜像都是使用dockerfile进行构建而不是dockercommit,...
- 自建私有云相册:Docker一键部署Immich,照片视频备份利器
-
自建私有云相册:Docker一键部署Immich,照片视频备份利器前言随着人们手机、PC、平板等电子产品多样,我们拍摄和保存的照片和视频数量也在不断增加。如何高效地管理和备份这些珍贵的记忆成为了一个重...
- docker容器的使用以及部署mysql
-
首先什么是docker官方:翻译:Docker是一个用于开发、发布和运行应用程序的开放平台。Docker使您能够将应用程序与基础架构分离,以便您可以快速交付软件。使用Docker,您可以像管理应...
-
- 自建Docker镜像加速服务,免费且简单,服务器VPS、NAS皆可用
-
写在前面:流程十分简单,有手就行,还请耐心看完。本文的实例仅做演示用,不久后将会删除,有需要的各位请自行搭建。免费实例如果15分钟内未收到入站流量,Render会关闭实例的网络服务。Render会在下次收到处理请求时重新启动该服务。Ren...
-
2025-05-24 15:40 mhr18
- 用了8年的方式-用 Docker 瞬间搭建本地开发环境
-
有些时候我们需要在本地搭开发环境,比如平时学习新技术的时候。或者有时候公司的项目需要在本地建一套类似的,方便调试修改。开发环境可能包括MySQL、Redis、Nginx、MQ、Elasticsea...
- 使用dockerfile构建docker镜像
-
准备工作购买vps使用ssh工具连接上1、更新系统aptupdate-y2、一键安装Dockercurl-fsSLhttps://get.docker.com-oget-docker.sh...
- 快速搭建 SpringCloud 微服务开发环境的脚手架
-
本文适合有SpringBoot和SpringCloud基础知识的人群,跟着本文可使用和快速搭建SpringCloud项目。本文作者:HelloGitHub-秦人HelloGitHub推出...
- Docker Hub最全详解(图文全面总结)
-
DockerHubDockerHub是一个由Docker公司负责维护的公共注册中心,它包含了超过15000多个可用来下载和构建容器的Docker镜像。DockerHub作用Docker好比一个代...
- Docker 命令详解
-
dockerimages—查看本地镜像命令dockerimages说明列出本地已下载的所有镜像及其标签、ID、大小等信息。适用场景查看本地镜像资源、准备删除或管理镜像时。常见用法docker...
- Kylin安装Dify
-
cd/mntgitclonehttps://github.com/langgenius/dify.gitcp/mnt/dify/docker/.env.example/mnt/dif...
- kali下对Docker的详细安装
-
Docker是渗透测试中必学不可的一个容器工具,在其中,我们能够快速创建、运行、测试以及部署应用程序。如,我们对一些漏洞进行本地复现时,可以使用Docker快速搭建漏洞环境,完成复现学习。注:本教程仅...
- 银河麒麟V10使用Docker方式部署应用
-
现在越来越多的企业级应用需要运行在国产化环境中,而银河麒麟V10是目前我碰到的最常用的服务器,在银河麒麟上部署应用有两种方式:使用二进制文件编译部署和使用Docker。关于使用二进制文件的方式...
- Docker入门到精通超详细教程,Docker全家桶实战攻略
-
大家好,我是各位双生的武魂、随身老爷爷。从看到这篇内容开始,你就是被选定的天命骚年,将承担起学完docker教程的使命,本使命为单向契约,你可选择YES或者选择YES。正式学习之前,我先给大家做一下d...
- 【Docker 新手入门指南】第一章:前言
-
一、基本介绍Docker介绍Docker是基于Go语言开发的开源容器化平台,旨在实现“一次镜像,处处运行”。它通过将应用程序及其依赖环境(代码、运行时、系统工具、系统库等)打包成一个轻量级、可移...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)