从单点 Redis 到 1 主 2 从 3 哨兵的架构演进之路
mhr18 2024-11-01 12:20 47 浏览 0 评论
一、前言
我们有个项目中用的 MySQL、Redis、ES、微服务都是单节点部署的,没有做集群模式部署,为了提高整体的可用性,对项目的部署架构进行了升级,支持高可用。相关内容可参考之前的两篇:
MySQL 高可用篇
ELK Stack 篇
通过本篇,你可以学到以下内容:
- Redis 真实的多服务器部署实战
- Redis 真实的主从模式部署实战。
- Redis 真实的哨兵集群模式部署实战。
- Redis 主节点宕机后,Redis 哨兵如何进行故障转移的。
- Redis 切换主节点后,客户端如何自动感知并连接新的主节点。
缓存实战的文章写了很多篇,把历史文章汇总下,方便大家查看:
《缓存实战(一)缓存初级打怪》
《缓存实战(二)Redis分布式锁》
《缓存实战(三)Redisson 分布式锁》
《缓存实战(四)实战 Spring Cache》
《缓存实战(五)Redis 开发手册 | 花果山版》
《缓存实战(六)详解 Redis 冷备》
《缓存实战(七)镜 | 深入剖析主从架构原理》
《缓存实战(八)「手摸手」主从环境的部署+压测》
二、部署拓扑图
我们项目的测试环境 12 台服务器已经部署好了,其中三台用来部署 Redis 的 一主 + 两从 + 三哨兵的服务器。服务器资源清单如下:
另外 Redis 的端口都是 6379,Sentinel(哨兵) 的端口都是 26379。
部署的拓扑图如下,三台服务器上都部署了一个哨兵。
三、搭建 Redis 一主两从
我们原来的单点的服务器上是有运行的 Redis 容器的,把这个容器的镜像打包备份下,然后拷贝和还原到新的服务器上就好了。
搭建 Redis 一主两从的步骤如下:
- 拷贝和还原 Redis 镜像到三台服务器上。
- 其中一台服务器作为主节点,配置文件为主节点的,用 docker 启动 Redis 主节点。
- 另外两台服务器作为从节点,配置文件为从节点的,用 docker 启动两个 Redis 从节点。
- 进入到主节点和从节点容器中,查看主从复制状态。
1.1 备份和还原 Redis 镜像
打包测试环境的 Redis 镜像,这个命令会将服务器上 redis 镜像打包成 tar 包,这样我们就方便拷贝到其他服务器上了。执行打包镜像命令:
sudo docker save -o redis.tar redis:0.1
因为保存的 tar 包权限不够,所以设置下权限为 777。执行修改权限的命令:
sudo chmod 777 redis.tar
将这个 tar 包拷贝新环境的三台服务器上。执行导入镜像的命令:
sudo docker load -i redis.tar
添加配置文件 redis.conf 放在本地,作为 redis 容器的配置文件。这个文件也可以在 redis 官网下载 https://redis.io/。redis.conf 文件放到 /home/redis 目录下。
sudo mkdir /home/redis
1.2 主节点配置
修改本地的 redis.conf 文件:
requirepass abc123
masterauth abc123
requirepass 和 masterauth:对于数据比较重要的节点,主节点会通过设置requirepass参数进行密码 验证,这时所有的客户端访问必须使用auth命令实行校验。从节点与主节点 的复制连接是通过一个特殊标识的客户端来完成,因此需要配置从节点的 masterauth参数与主节点密码保持一致,这样从节点才可以正确地连接到主 节点并发起复制流程。
1.3 从节点配置
slave-read-only yes
requirepass abc123
masterauth abc123
slaveof 10.2.1.61 6379
1.4 启动容器
需要注意的是需要映射本地文件夹。
sudo docker run -p 6379:6379 --restart=always --name redis \
-v /home/redis/redis.conf:/usr/local/etc/redis/redis.conf \
-v /home/redisdata:/data/ \
-d 301
-v 代表映射的文件或文件夹,这里映射了 redis.conf 文件和 data 目录。data 目录会存放 Redis 的 AOF 和 RDB 持久化文件。
-d 表示后台运行,46b 代表镜像 id。因为我们服务器是没有外网的,所以用的是本地镜像启动的,如果你的服务器有外网,完全可以用官网的 redis 镜像启动。
1.5 查看 Redis 状态
进入容器,连接 redis,node1的 redis 密码是 abc123
# 查询容器 id
docker ps
# 进入 mysql 容器
docker exec -it <容器 id> /bin/bash
# 连接 redis
redis-cli -h localhost -p 6379 -a abc123
# 查看复制信息
info replication
只启动 node1 时查看 redis 复制信息
可以看到 role:master 信息,代表当前节点作为主节点。
connected_slaves:0 代表连接的从节点为 0 个。
当三个节点的 redis 容器都启动后,再次查看主节点的复制信息。发现有 connected_slaves:2 有两个从节点连上了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QPHj8Ohi-1654673955923)(../../images/image-20220608111236463.png)]
然后我们进入到从节点容器,查看从节点的复制信息。
发现 role:slave,说明此节点作为从节点。
master_host:10.2.1.61,说明了主节点的 IP 是 10.2.1.61。
1.6 测试主从复制
我们可以用 Redis Desktop 工具测试主从数据是否一致。在主节点中写入 abc=当前时间,发现另外两个从节点也同步了这个数据,说明主从复制成功。
四、搭建哨兵集群
4.1 哨兵集群拓扑图
三台机器上分别部署三个哨兵服务。部署拓扑图如下所示:
4.2 哨兵服务是怎么启动的
其实哨兵服务也是用 Redis 容器启动的,只是用的不同命令的启动的。
我们可以在 redis 容器中执行如下命令启动哨兵服务。
redis-sentinel /usr/local/etc/redis/sentinel.conf
因为我们是通过 docker 启动的,所以在启动 docker 容器时,带上这个命令参数就可以启动哨兵服务了,就不用到容器里面执行这个命令了。
4.3 哨兵配置
首先创建两个映射文件:sentinel.conf 和 sentinel-26379.log,第一个是配置哨兵参数的,第二个文件是哨兵的日志文件,这两个文件都会在启动 redis 容器时,映射到容器中,方便我们修改配置以及查看日志。
sentinel.conf 这个配置文件可以从官方的 redis 安装包中拷贝,也可以自己创建一个配置文件,修改几个参数就可以了。可以直接拷贝我的配置。
mkdir /home/redis
vim /home/redis/sentinel.conf
配置内容如下:
# sentile 端口
port 26379
# 是否在后台启动,默认为 no,注意这里需要设置为 no,否则容器启动不起来。
daemonize no
pidfile /var/run/redis-sentinel.pid
# 日志文件
logfile /var/log/sentinel-26379.log
# 工作目录
dir /tmp
# 监控 redis 的 IP 和端口,这里监控的 redis 的主节点
sentinel monitor mymaster 10.2.1.61 6379 2
# down-after-milliseconds:每个 Sentinel节点都要通过定期发送 ping 命令来判断Redis数据节点和其 余Sentinel节点是否可达,如果超过了down-after-milliseconds配置的时间且没 有有效的回复,则判定节点不可达,<times>(单位为毫秒)就是超时时 间。这个配置是对节点失败判定的重要依据。对 Sentinel节点、主节点、从节点的失败判定同时有效。
sentinel down-after-milliseconds mymaster 30000
# parallel-syncs 就是用来限制在一次故障转移之后,每次向新的主节 点发起复制操作的从节点个数。
sentinel parallel-syncs mymaster 1
# 故障转移超时时间
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
# 当 redis 主从复制配置了密码的话,则需要在这里配置密码
sentinel auth-pass mymaster WHredis2020!
- daemonize:是否在后台启动,默认为 no,注意这里需要设置为 no,否则容器启动不起来。
- logfile:日志文件,哨兵监控和故障转移的日志都会存到这个日志里面。
- sentinel monitor mymaster:监控 redis 的 IP 和端口,这里监控的 redis 的主节点。
- down-after-milliseconds:每个 Sentinel节点都要通过定期发送 ping 命令来判断Redis数据节点和其 余Sentinel节点是否可达,如果超过了down-after-milliseconds配置的时间且没 有有效的回复,则判定节点不可达,(单位为毫秒)就是超时时间。这个配置是对节点失败判定的重要依据。对 Sentinel节点、主节点、从节点的失败判定同时有效。
- parallel-syncs:就是用来限制在一次故障转移之后,每次向新的主节 点发起复制操作的从节点个数。
- failover-timeout:故障转移超时时间。
- auth-pass:当 redis 主从复制配置了密码的话,则需要在这里配置密码。
首先在本地创建日志文件用来存放哨兵日志。
mkdir /home/redis/sentinel
vim /home/redis/sentinel/sentinel-26379.log
4.4 启动哨兵容器
4.4.1 启动一个 sentinel 容器
docker run --name mysentinel1 --restart=always -p 26379:26379 \
-v /home/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf \
-v /home/redis/sentinel/sentinel-26379.log:/var/log/sentinel-26379.log \
-d 9a2f \
redis-sentinel /usr/local/etc/redis/sentinel.conf
- --name mysentinel1,指定哨兵容器的名称为 mysentinel1。
- --restart=always,重启机器后,自动重启容器。
- -v,挂载哨兵配置文件和日志文件。
这里的 -d 9a2f 是 本地的 redis 容器 id,因为本机没有网络,所以这个镜像是从其他有网络的机器加载进来的。如果你们的机器有网络,完全可以用 -d redis 参数替换,也就是使用最新的 redis 镜像来启动 sentinel。
查看启动的容器,第一个是哨兵容器,名字是 mysentinel1, 第二个是 redis 容器,名字是 redis。如下图所示:
当在三台服务器上分别启动 Redis 哨兵后,查看哨兵日志文件 sentinel-26379.log。
打印出了 Redis 的当前版本(5.0.14),运行模式(哨兵模式),端口号 26379,哨兵 id,监控的 Redis 中的主节点,两个 Redis 从节点和一个主节点的 IP 和 端口。
而且当我们去查看 Sentinel 配置文件时,发现配置文件中的内容发生了变化,在文件末尾追加了以下内容,含义就是 Sentinel 自动发现了其他 Redis 从节点
4.4.2 启动第二个容器
执行以下命令启动第二个容器:
docker run --name mysentinel2 --restart=always -p 26379:26379 \
-v /home/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf \
-v /home/redis/sentinel/sentinel-26379.log:/var/log/sentinel-26379.log \
-d 9a2f \
redis-sentinel /usr/local/etc/redis/sentinel.conf
4.4.3 启动第三个容器
执行以下命令启动第三个容器:
docker run --name mysentinel3 --restart=always -p 26379:26379 \
-v /home/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf \
-v /home/redis/sentinel/sentinel-26379.log:/var/log/sentinel-26379.log \
-d 9a2f \
redis-sentinel /usr/local/etc/redis/sentinel.conf
4.4.4 验证 Redis 主从切换
停掉主节点的 redis 容器后,进入到第二个哨兵容器中,执行以下命令查看哨兵的状态:
redis-cli -h 127.0.0.1 -p 26379 info Sentinel
发现主节点的 IP 已经从 10.2.1.61 切换为从节点的 IP(10.2.1.63)了。
进入到第二个 redis 容器中,查看同步状态。主节点的 IP 也是 10.2.1.63
查看第三个哨兵的日志,可以看到哨兵通过以下步骤进行了主从切换。
重要的步骤说明如下:
- ① 主观宕机,+sdown 表示当前哨兵认为这个 Redis 节点(10.2.1.61)宕机了。
- ② 客观宕机,+odown 表示有几个哨兵认为这个 Redis 节点(10.2.1.61)宕机了。看到的 quorun 4/2,表示有 4 个哨兵认为 Redis 节点宕机了,大于设置的 2,所以这个 Redis 节点是真的宕机了。(这里为什么是 4,而不是哨兵数 3,笔者也没有弄清楚,欢迎留言讨论。)
- ③ 投票选举新的哨兵 Leader,三个哨兵都将票投给了 id = 2abxxx 的哨兵,也就是第三个哨兵节点,将由这个哨兵进行主从切换。
- ④ 开始故障转移,failover-state-select-slave 表示要转移哪个故障节点。这里就是切换主节点。
- ⑤ 选出主节点为第三个 Redis 节点(10.2.1.63)。
- ⑥ 切换主节点为第三个 Redis 节点(10.2.1.63)。
说明哨兵集群模式下对 Redis 的状态监控和主从切换成功。
五、客户端自动感知故障
如何实现自动感知故障
我们项目中,都是用 Redis 客户端去读写 Redis,在单机情况下,单节点 Redis 宕机后,客户端肯定会报错,我们可以尝试恢复这个服务器上的 Redis 就好了。
但是我们现在是有多个 Redis 节点的,应用程序该如何配置呢?
可能的思路是这样:应用程序配置主节点的 IP 地址和端口。缺点:主节点切换后,需要改配置并重启应用。
那有没有一种方案是自动感知到 Redis 宕机后,连接到新的主节点的呢?
有的,我们加下 Redis 的哨兵配置就可以了。配置内容如下所示:
spring:
redis:
database: 0
password: abc123 # 密码(默认为空)
timeout: 10000 # 连接超时时长(毫秒)
sentinel: #哨兵模式
master: mymaster #主服务器所在集群名称
nodes: 10.2.1.63:26379,10.2.1.62:26379,10.2.1.61:26379
配置好了后,重启应用程序,然后停掉 Redis 主节点的容器。测试往 redis 写入数据,程序会报错。
写入数据的代码:
stringRedisTemplate.opsForValue()
.setIfAbsent(key, toJson(value),
millisecond, TimeUnit.MILLISECONDS);
报错信息如下:
nested exception is redis.clients
.jedis.exceptions.JedisConnectionException:
Unexpected end of stream.
因为故障转移是需要一定时间的,过几秒后后发现控制台窗口打印出 Redis 的主节点为 10.2.1.63:6379,说明故障转移成功了。
[MasterListener-mymaster-[10.2.1.61:26379]]
INFO redis.clients.jedis.JedisSentinelPool
-Created JedisPool to master at
10.2.1.63:6379
再次测试读写 Redis,都是正常的,且往第三个节点写入数据后,第二个节点也进行了主从复制。
客户端自动感知的原理
我们项目中用的 Jedis 客户端,它有一个连接池 JedisPool,当访问 Redis 时,会从连接池里面获取一个连接。我们看下这个连接池里面的信息。如下图所示:
- masterListeners 代表对三个 Redis 节点的监听器。里面指定了 Redis 节点的 IP 和 Port。
- currentHostMaster 代表当前连接的主节点。目前为第三个节点。
当我们停掉 Redis 主节点后,哨兵会切换主节点,这个连接池里面的 currentHostMaster 也会被更新为新的主节点。当我们再次访问 Redis 时,会和新的主节点建立连接。
六、遇到的问题
6.1 提示不能写只读的 redis 节点
READONLY You can't write against a read only replica.;
解决方案:每个哨兵都需要配置成监控主节点 node1 的 IP。
6.2 提示连接 Redis 失败
ERR Client sent AUTH, but no password is set
解决方案:主从节点都需要配置 requirepass 和 masterauth。
七、总结
本篇讲解了在真实的多台服务器上如何部署 Redis 主从架构、哨兵集群,以及验证主从复制和故障转移。
然后对项目中使用 Redis 的地方,加入了哨兵配置,使其可以自动感知主从切换后的 IP 变化,从而和新的 Redis 主节点进行连接。
Redis Cluster 集群模式并没有涉及到,大家有没有兴趣呢~~
来源:https://mp.weixin.qq.com/s/COGUwH-u5NJgAM5O53w9oQ
相关推荐
- Java培训机构,你选对了吗?(java培训机构官网)
-
如今IT行业发展迅速,不仅是大学生,甚至有些在职的员工都想学习java开发,需求量的扩大,薪资必定增长,这也是更多人选择java开发的主要原因。不过对于没有基础的学员来说,java技术不是一两天就能...
- 产品经理MacBook软件清单-20个实用软件
-
三年前开始使用MacBookPro,从此再也不想用Windows电脑了,作为生产工具,MacBook可以说是非常胜任。作为产品经理,值得拥有一台MacBook。MacBook是工作平台,要发挥更大作...
- RAD Studio(Delphi) 本月隆重推出新的版本12.3
-
#在头条记录我的2025#自2024年9月,推出Delphi12.2版本后,本月隆重推出新的版本12.3,RADStudio12.3,包含了Delphi12.3和C++builder12.3最...
- 图解Java垃圾回收机制,写得非常好
-
什么是自动垃圾回收?自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未使用中的对象(未引用...
- Centos7 初始化硬盘分区、挂载(针对2T以上)添加磁盘到卷
-
1、通过命令fdisk-l查看硬盘信息:#fdisk-l,发现硬盘为/dev/sdb大小4T。2、如果此硬盘以前有过分区,则先对磁盘格式化。命令:mkfs.文件系统格式-f/dev/sdb...
- 半虚拟化如何提高服务器性能(虚拟化 半虚拟化)
-
半虚拟化是一种重新编译客户机操作系统(OS)将其安装在虚拟机(VM)上的一种虚拟化类型,并在主机操作系统(OS)运行的管理程序上运行。与传统的完全虚拟化相比,半虚拟化可以减少开销,并提高系统性能。虚...
- HashMap底层实现原理以及线程安全实现
-
HashMap底层实现原理数据结构:HashMap的底层实现原理主要依赖于数组+链表+红黑树的结构。1、数组:HashMap最底层是一个数组,称为table,它存放着键值对。2、链...
- long和double类型操作的非原子性探究
-
前言“深入java虚拟机”中提到,int等不大于32位的基本类型的操作都是原子操作,但是某些jvm对long和double类型的操作并不是原子操作,这样就会造成错误数据的出现。其实这里的某些jvm是指...
- 数据库DELETE 语句,还保存原有的磁盘空间
-
MySQL和Oracle的DELETE语句与数据存储MySQL的DELETE操作当你在MySQL中执行DELETE语句时:逻辑删除:数据从表中标记为删除,不再可见于查询结果物理...
- 线程池—ThreadPoolExecutor详解(线程池实战)
-
一、ThreadPoolExecutor简介在juc-executors框架概述的章节中,我们已经简要介绍过ThreadPoolExecutor了,通过Executors工厂,用户可以创建自己需要的执...
- navicat如何使用orcale(详细步骤)
-
前言:看过我昨天文章的同鞋都知道最近接手另一个国企项目,数据库用的是orcale。实话实说,也有快三年没用过orcale数据库了。这期间问题不断,因为orcale日渐消沉,网上资料也是真真假假,难辨虚...
- 你的程序是不是慢吞吞?GraalVM来帮你飞起来性能提升秘籍大公开
-
各位IT圈内外的朋友们,大家好!我是你们的老朋友,头条上的IT技术博主。不知道你们有没有这样的经历:打开一个软件,半天没反应;点开一个网站,图片刷不出来;或者玩个游戏,卡顿得想砸电脑?是不是特别上火?...
- 大数据正当时,理解这几个术语很重要
-
目前,大数据的流行程度远超于我们的想象,无论是在云计算、物联网还是在人工智能领域都离不开大数据的支撑。那么大数据领域里有哪些基本概念或技术术语呢?今天我们就来聊聊那些避不开的大数据技术术语,梳理并...
- 秒懂列式数据库和行式数据库(列式数据库的特点)
-
行式数据库(Row-Based)数据按行存储,常见的行式数据库有Mysql,DB2,Oracle,Sql-server等;列数据库(Column-Based)数据存储方式按列存储,常见的列数据库有Hb...
- AMD发布ROCm 6.4更新:带来了多项底层改进,但仍不支持RDNA 4
-
AMD宣布,对ROCm软件栈进行了更新,推出了新的迭代版本ROCm6.4。这一新版本里,AMD带来了多项底层改进,包括更新改进了ROCm的用户空间库和AMDKFD内核驱动程序之间的兼容性,使其更容易...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (56)
- oracle 乐观锁 (53)
- 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)