当前位置: 首页 > 科技观察

从单点Redis到1主2从3哨兵架构演进路径

时间:2023-03-15 09:12:34 科技观察

1.前言我们一个项目中用到的MySQL、Redis、ES、微服务都是单节点部署,没有采用集群模式部署。为了提高整体可用性,对项目的部署架构进行了升级,支持高可用。通过本文,您可以了解到以下内容:Redis实战多机部署实战Redis实战主从模式部署实战。Redis真正的哨兵集群模式部署。Redismaster节点宕机后,Redissentinelfailover是如何进行的。Redis切换主节点后,客户端如何自动感知并连接到新的主节点。2、部署拓扑我们项目的测试环境部署了12台服务器,其中3台用于部署Redis服务器,一主+二从+三哨兵。服务器资源列表如下:另外Redis的端口是6379,Sentinel的端口是26379,部署的拓扑图如下,在三台服务器上部署一个sentinel。3、搭建一主二从的Redis。我们原来的单点服务器有一个正在运行的Redis容器。打包备份这个容器的镜像,然后复制还原到新的服务器上。一主两从搭建Redis的步骤如下:将Redis镜像复制还原到三台服务器。其中一台服务器作为主节点,配置文件作为主节点。使用docker启动Redis主节点。另外两台服务器作为从节点,配置文件为从节点。使用docker启动两个Redis从节点。分别进入主节点和从节点容器,查看主从复制状态。1、备份和恢复Redis镜像打包测试环境的Redis镜像。该命令会将服务器上的redis镜像打包成一个tar包,这样我们就可以方便的复制到其他服务器上。执行打包镜像命令:sudodockersave-oredis.tarredis:0.1由于保存的tar包权限不足,设置权限为777。执行命令修改权限:sudochmod777redis.tar将这个tar包复制到新环境中的三台服务器。执行导入镜像的命令:sudodockerload-iredis.tar在本地添加配置文件redis.conf作为redis容器的配置文件。这个文件也可以从redis官网https://redis.io/下载。redis.conf文件放在/home/redis目录下。须藤mkdir/home/redis2.Master节点配置修改本地redis.conf文件:requirepassabc123masterauthabc123requirepassandmasterauth:对于有比较重要数据的节点,master节点会通过设置requirepass参数进行密码校验。此时,所有客户端访问都必须使用auth命令进行验证。从节点和主节点之间的复制连接是通过一个专门标识的客户端完成的,所以需要配置从节点的masterauth参数与主节点的密码一致,这样从节点才能正确连接到主节点并启动复制过程。3.configureslave-read-onlyyesrequirepassabc123masterauthabc123slaveof10.2.1.6163791.4从节点启动容器4.需要注意的是启动容器时需要映射本地文件夹。sudodockerrun-p6379:6379--restart=always--nameredis\-v/home/redis/redis.conf:/usr/local/etc/redis/redis.conf\-v/home/redisdata:/data/\-d301-v表示映射的文件或文件夹,这里映射的是redis.conf文件和data目录。data目录会存放Redis的AOF和RDB持久化文件。-d表示后台运行,46b表示图像ID。因为我们的服务器没有外网,所以我们使用本地镜像启动。如果你的服务器有外网,可以使用官网的redis镜像启动。5、查看Redis的状态进入容器,连接redis,node1的redis密码是abc123。#查询容器iddockerps#进入mysql容器dockerexec-it/bin/bash#连接redisredis-cli-hlocalhost-p6379-aabc123#查看复制信息inforeplication只有在node1时才能查看启动后的Redis复制信息可以看到role:master信息,表示当前节点为主节点。connected_slaves:0表示有0个连接的从节点。三个节点的redis容器全部启动后,再次查看master节点的复制信息。发现有connected_slaves:2,连接了两个slave节点。[外链图片传输失败,源站可能有防盗链接机制,建议保存图片直接上传(img-QPHj8Ohi-1654673955923)(../../images/image-20220608111236463.png)]然后我们进入Fromthenodecontainer,查看从节点的复制信息。发现role:slave,说明这个节点是slave节点。master_host:10.2.1.61,表示master节点的IP为10.2.1.61。6、测试主从复制我们可以使用RedisDesktop工具来测试主从数据是否一致。在主节点写入abc=当前时间,发现另外两个从节点也同步了这个数据,说明主从复制成功。四、搭建Sentinel集群1.Sentinel集群拓扑图在三台机器上分别部署三个Sentinel服务。部署拓扑图如下:2.哨兵服务是如何启动的?其实sentinel服务也是用Redis容器启动的,只是命令不同而已。我们可以在redis容器中执行如下命令来启动sentinel服务。redis-sentinel/usr/local/etc/redis/sentinel.conf因为我们是通过docker启动的,所以在启动docker容器的时候,可以通过这个命令参数启动sentinel服务,所以不需要在里面执行这个命令容器起来。3.sentinel配置首先创建两个映射文件:sentinel.conf和sentinel-26379.log,第一个是配置sentinel参数,第二个文件是sentinel的日志文件,启动时都会用到rediscontainer,映射到容器中,方便我们修改配置和查看日志。sentinel.conf这个配置文件可以从redis官方安装包里拷贝过来,也可以自己创建一个配置文件,修改几个参数。你可以直接复制我的配置。mkdir/home/redisvim/home/redis/sentinel.conf配置内容如下:#sentileportport26379#是否后台启动,默认是no,注意需要设置为no,否则容器将不会启动。daemonizenopidfile/var/run/redis-sentinel.pid#logfilelogfile/var/log/sentinel-26379.log#workingdirectorydir/tmp#监控redis的IP和端口,这里监控redis的master节点sentinelmonitormymaster10.2.1.6163792#down-after-milliseconds:每个Sentinel节点必须周期性发送ping命令来判断Redis数据节点和其他Sentinel节点是否可达。如果超过down-after-milliseconds配置时间,没有有效回复,则判定该节点不可达,(毫秒)为超时时间。该配置是判断节点故障的重要依据。Sentinel节点、主节点、从节点的故障判断同时有效。sentineldown-after-millisecondsmymaster30000#parallel-syncs用于限制故障转移后每次向新主节点发起复制操作的从节点数量。sentinelparallel-syncsmymaster1#failovertimeoutsentinelfailover-timeoutmymaster180000sentineldeny-scripts-reconfigyes#当redis主从复制配置密码时,这里需要配置密码sentinelauth-passmymasterWHredis2020!daemonize:yes后台启动,默认是no,注意需要设置成no,否则容器不会启动。logfile:日志文件,哨兵监控和故障转移日志将存储在该日志中。sentinelmonitormymaster:监控redis的IP和端口,这里监控的是redis的master节点。down-after-milliseconds:每个Sentinel节点必须周期性发送ping命令来判断Redis数据节点和其他Sentinel节点是否可达。如果超过了down-after-milliseconds配置的时间,没有有效回复,则节点被判定为Unreachable,(单位毫秒)为超时时间。该配置是判断节点故障的重要依据。Sentinel节点、主节点、从节点的故障判断同时有效。parallel-syncs:用于限制故障转移后每次向新主节点发起复制操作的从节点数量。failover-timeout:故障切换超时时间。auth-pass:redis主从复制配置密码时,这里需要配置密码。首先在本地创建一个日志文件,用来存放Sentinel日志。mkdir/home/redis/sentinelvim/home/redis/sentinel/sentinel-26379.log4.启动sentinel容器4.1启动一个sentinel容器dockerrun--namemysentinel1--restart=always-p26379:26379\-v/home/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf\-v/home/redis/sentinel/sentinel-26379.log:/var/log/sentinel-26379.log\-d9a2f\redis-sentinel/usr/local/etc/redis/sentinel.conf--namemysentinel1,指定sentinel容器的名称为mysentinel1。--restart=always,重启机器后,自动重启容器。-v,挂载哨兵配置文件和日志文件。这里-d9a2f是本地的redis容器id,因为本机没有网络,所以这个镜像是从其他有网络的机器上加载的。如果你的机器有网络,可以使用-dredis参数来代替,即使用最新的redis镜像来启动sentinel。查看启动的容器,第一个是sentinel容器,名字是mysentinel1,第二个是redis容器,名字是redis。如下图所示:在三台服务器上启动RedisSentinel后,查看Sentinel日志文件sentinel-26379.log。打印出Redis当前版本(5.0.14)、运行模式(哨兵模式)、端口号26379、sentinelid、被监控Redis中的主节点、两台Redis从节点和一台主节点的IP和端口。而我们去查看Sentinel配置文件的时候,发现配置文件里面的内容发生了变化,在文件末尾增加了如下内容,也就是说Sentinel自动从4.2节点发现了其他Redis。启动第二个容器,执行如下命令启动第二个容器第一个容器:dockerrun--namemysentinel2--restart=always-p26379:26379\-v/home/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf\-v/home/redis/sentinel/sentinel-26379.log:/var/log/sentinel-26379.log\-d9a2f\redis-sentinel/usr/local/etc/redis/sentinel.conf4.3启动第三个容器执行如下命令启动第三个容器:dockerrun--namemysentinel3--restart=always-p26379:26379\-v/home/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf\-v/home/redis/sentinel/sentinel-26379.log:/var/log/sentinel-26379.log\-d9a2f\redis-sentinel/usr/local/etc/redis/sentinel.conf4.4验证Redis主从切换是否停止开启master节点的redis容器后,进入第二个sentinel容器,执行如下命令查看sentinel的状态:redis-cli-h127.0.0.1-p26379infoSentinel发现ma的IPsternodehasbeenswitchedfrom10.2.1.61toslave节点(10.2.1.63)的IP已启动。进入第二个redis容器查看同步状态。主节点的IP也是10.2.1.63。查看第三个哨兵的日志,可以看到哨兵通过以下步骤进行了主从切换。重要步骤解释如下:①主观宕机,+sdown表示当前sentinel认为Redis节点(10.2.1.61)宕机。②客观宕机,+odown表示多个哨兵认为Redis节点(10.2.1.61)宕机。你看到的quorun4/2是说有4个sentinel认为Redis节点宕机了,大于集合2,所以Redis节点真的宕机了。(为什么是4个而不是3个sentinel节点,主从切换会由这个sentinel进行。④启动failover,failover-state-select-slave表示转移到哪个故障节点,这里是切换master节点。⑤selectmaster节点作为第三个Redis节点(10.2.1.63)⑥将主节点切换为第三个Redis节点(10.2.1.63),说明哨兵集群模式下Redis的状态监控和主从切换成功5.客户端如何自动检测故障如何实现故障自动检测我们项目中使用Redis客户端读写Redis,在单机的情况下,单节点Redis挂掉后,客户端肯定会报错,我们可以尝试在服务器上恢复这个Redis就好了。但是现在我们有多个Redis节点,应用应该怎么配置呢?可能的思路是这样的:应用配置master的IP地址和端口node.缺点:在m之后aster节点被切换,需要更改配置并重启应用程序。有没有Redis宕机后自动连接到新master节点的解决方案?是的,我们可以添加Redis的哨兵配置。配置内容如下:spring:redis:database:0password:abc123#密码(默认为空)timeout:10000#连接超时时间(毫秒)sentinel:#sentinelmodemaster:mymaster#master所在的集群名称serverislocatednodes: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);报错信息如下:nestedexceptionisredis.clients.jedis.exceptions.JedisConnectionException:Unexpectedendofstream。因为故障转移需要一定的时间,几秒后控制台窗口打印出Redis的主节点为10.2.1.63:6379,说明故障转移成功。[MasterListener-mymaster-[10.2.1.61:26379]]INFOredis.clients.jedis.JedisSentinelPool-CreatedJedisPooltomasterat10.2.1.63:6379再次测试读写Redis,正常,写入第三个节点后数据导入完毕,第二个节点也进行主从复制。客户端自动感知原理我们项目中使用的Jedis客户端有一个连接池JedisPool。访问Redis时,会从连接池中获取一个连接。我们看一下这个连接池中的信息。如下图所示:masterListeners代表三个Redis节点的监听器。它指定了Redis节点的IP和端口。currentHostMaster代表当前连接的主节点。目前是第三个节点。当我们停止Redis主节点时,哨兵会切换主节点,连接池中的currentHostMaster也会更新为新的主节点。当我们再次访问Redis时,会与新的主节点建立连接。六、遇到的问题1.提示不能写入只读redis节点READONLYYoucan'twriteagainstareadonlyreplica.;解决方案:每个sentinel都需要配置监听master节点node1的IP。2.提示连接Redis失败ERRClientsentedAUTH,butnopasswordisset解决方法:master和slave节点都需要配置requirepass和masterauth。7.小结本文讲解如何在多台真实服务器上部署Redis主从架构、sentinel集群,以及验证主从复制和故障转移。然后在项目中使用Redis的地方,增加一个sentinel配置,使其在主从切换后自动感知IP变化,从而与新的Redis主节点连接。