侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 285 篇文章
  • 累计创建 125 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Docker教程-6-在Redis主从复制基础上搭建哨兵模式

孔子说JAVA
2021-10-19 / 0 评论 / 0 点赞 / 118 阅读 / 10,609 字 / 正在检测是否收录...

本教程基于《Docker教程-5-基于Docker的Redis主从复制》,所有的配置和服务都在其基础上,最终搭建一套1主2从3哨兵的redis服务。

  • redis容器的安装配置参考:Docker教程-4-Redis容器的安装配置使用
  • 主从复制服务器搭建参考: Docker教程-5-基于Docker的Redis主从复制

1、为什么需要哨兵

1.1 哨兵模式解决的问题

redis主从模式解决了数据备份和单例可能存在的性能问题,但是也引入了新的问题。

  • 由于主从模式配置了三个redis实例,并且每个实例都使用不同的ip(如果在不同的机器上)和端口号,根据前面所述,主从模式下可以将读写操作分配给不同的实例进行从而达到提高系统吞吐量的目的,但也正是因为这种方式造成了使用上的不便,因为每个客户端连接redis实例的时候都是指定了ip和端口号的,如果所连接的redis实例因为故障下线了,而主从模式也没有提供一定的手段通知客户端另外可连接的客户端地址,因而需要手动更改客户端配置重新连接。
  • 另外,主从模式下,如果主节点由于故障下线了,那么从节点因为没有主节点而同步中断,因而需要人工进行故障转移工作。

redis在2.8版本之后正式提供了sentinel(哨兵)架构。关于sentinel,这里需要说明几个概念:

image-1649047089034

每个sentinel节点其实就是一个redis实例,与主从节点不同的是sentinel节点作用是用于监控redis数据节点的,而sentinel节点集合则表示监控一组主从redis实例多个sentinel监控节点的集合,比如有主节点master和从节点slave-1、slave-2,为了监控这三个主从节点,这里配置N个sentinel节点sentinel-1,sentinel-2,…,sentinel-N。如下图是sentinel监控主从节点的示例图:

image-1649047172879

从图中可以看出,对于一组主从节点,sentinel只是在其外部额外添加的一组用于监控作用的redis实例。在主从节点和sentinel节点集合配置好之后,sentinel节点之间会相互发送消息,以检测其余sentinel节点是否正常工作,并且sentinel节点也会向主从节点发送消息,以检测监控的主从节点是否正常工作。

前面讲到,sentinel架构的主要作用是解决主从模式下主节点的故障转移工作的。这里如果主节点因为故障下线,那么某个sentinel节点发送检测消息给主节点时,如果在指定时间内收不到回复,那么该sentinel就会主观的判断该主节点已经下线,那么其会发送消息给其余的sentinel节点,询问其是否“认为”该主节点已下线,其余的sentinel收到消息后也会发送检测消息给主节点,如果其认为该主节点已经下线,那么其会回复向其询问的sentinel节点,告知其也认为主节点已经下线,当该sentinel节点最先收到超过指定数目(配置文件中配置的数目和当前sentinel节点集合数的一半,这里两个数目的较大值)的sentinel节点回复说当前主节点已下线,那么其就会对主节点进行故障转移工作,故障转移的基本思路是在从节点中选取某个从节点向其发送slaveof no one(假设选取的从节点为127.0.0.1:6380),使其称为独立的节点(也就是新的主节点),然后sentinel向其余的从节点发送slaveof 127.0.0.1 6380命令使它们重新成为新的主节点的从节点。重新分配之后sentinel节点集合还会继续监控已经下线的主节点(假设为127.0.0.1:6379),如果其重新上线,那么sentinel会向其发送slaveof命令,使其成为新的主机点的从节点,如此故障转移工作完成。

1.2 哨兵模式的优缺点

哨兵模式的优点:

  • 相比主从模式,可以实现⾃动主从切换(故障转移),可⽤性更⾼

哨兵模式的缺点:

  • 主从切换需要消耗一定的时间会丢失短暂数据(这时无法写和读)
  • 主节点的写能力和存储能力受限(还是只有主节点可以写,存储能力还是处于单节点,因为主节点存的数据和其他节点一模一样,主节点存不下了,也就无法继续写了,存储就达到了上限了,数据不是分片存储的)

2、主从容器相关配置

若使用 docker run 命令创建主从容器的时候,没有暴露 sentinel 哨兵(默认端口26379)的端口,需要重新创建主从容器,可按照以下步骤操作;若已暴露了sentinel的哨兵端口,则跳过该步骤。

  • 重点:不仅要暴露redis端口,也要暴露sentinel哨兵的端口,即容器启动时的端口映射要映射两个端口。

2.1 删除1主2从3个容器

使用 docker rm -f 容器id或容器名称 删除容器,该命令可以在不停止容器的情况下直接删除。

# 删除主容器(docker-redis-master)、从容器1(docker-redis-slave1)、从容器2(docker-redis-slave2)
docker rm -f docker-redis-master
docker rm -f docker-redis-slave1
docker rm -f docker-redis-slave2

image-1649047375666

2.2 启动1主2从3个容器

按照主从顺序启动1主2从3个容器。

# 启动运行主容器命令,-p 7011:6379暴露了redis端口,-p 26379:26379暴露了sentinel哨兵的端口
docker run -it -p 7011:6379 -p 26379:26379 \
--name docker-redis-master \
--privileged=true \
--restart=always \
-v /usr/local/docker/redis-cluster/redis6-1/7011/conf/redis.conf:/etc/redis/redis.conf \
-v /usr/local/docker/redis-cluster/redis6-1/7011/data:/data \
-v /etc/localtime:/etc/localtime \
-e TZ="Asia/Shanghai" \
-d redis:6.2.6 redis-server /etc/redis/redis.conf


# 启动运行从容器1的命令
docker run -it -p 7012:6379  -p 26380:26379 \
--name docker-redis-slave1 \
--privileged=true \
--restart=always \
-v /usr/local/docker/redis-cluster/redis6-1/7012/conf/redis.conf:/etc/redis/redis.conf \
-v /usr/local/docker/redis-cluster/redis6-1/7012/data:/data \
-v /etc/localtime:/etc/localtime \
-e TZ="Asia/Shanghai" \
-d redis:6.2.6 redis-server /etc/redis/redis.conf


# 启动运行从容器2的命令
docker run -it -p 7013:6379 -p 26381:26379 \
--name docker-redis-slave2 \
--privileged=true \
--restart=always \
-v /usr/local/docker/redis-cluster/redis6-1/7013/conf/redis.conf:/etc/redis/redis.conf \
-v /usr/local/docker/redis-cluster/redis6-1/7013/data:/data \
-v /etc/localtime:/etc/localtime \
-e TZ="Asia/Shanghai" \
-d redis:6.2.6 redis-server /etc/redis/redis.conf

image-1649047415041

使用 docker ps 命令查看容器启动状态,可以看到1主2从个容器均已正常启动。

image-1649047435749

2.3 查看容器ip,确定是否修改配置文件

查看1主2从3个容器的ip,确定是否修改配置文件redis.conf。可以通过 docker inspect 容器id或容器名称 命令查看容器的详情信息(IPAddress部分有容器IP),也可以通过 docker inspect --format '{{ .NetworkSettings.IPAddress }}' 容器id或容器名称 命令查看容器的IP。通过命令查看到主从容器ip分别为172.17.0.9、172.17.0.10、172.17.0.11。

docker inspect --format '{{ .NetworkSettings.IPAddress }}' docker-redis-master
docker inspect --format '{{ .NetworkSettings.IPAddress }}' docker-redis-slave1
docker inspect --format '{{ .NetworkSettings.IPAddress }}' docker-redis-slave2

image-1649047483585

查看主从3个配置文件redis.conf中的bind,slaveof项是否匹配,若不匹配需要更改配置文件,然后重启主从容器。

# 重启主从容器
docker restart docker-redis-master 
docker restart docker-redis-slave1
docker restart docker-redis-slave2

# 或先关闭容器再启动
# 关闭容器
docker stop docker-redis-master 
docker stop docker-redis-slave1
docker stop docker-redis-slave2
# 启动容器,先启动主容器
docker start docker-redis-master 
docker start docker-redis-slave1
docker start docker-redis-slave2

2.4 附:1主2从的配置

1)主容器的配置文件

启动主容器的命令中挂载了配置文件在宿主机中的完整路径 /usr/local/docker/redis-cluster/redis6-1/7011/conf/redis.conf。具体内容如下。

# port表示redis容器的端口
port 6379

# bind表示绑定主服务容器的IP, 配置的2个ip表示同时绑定了2个ip,
# bing 0.0.0.0 表示对ip没有限制
# 该项可以不配置,若配置则该项可能有所不同
bind 172.17.0.9 127.0.0.1
 
# RDB相关配置
save 900 1
save 300 10
save 60 10000
rdbcompression yes
 
# 数据目录
dir /data
 
# AOF相关配置
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
 
# 密码
requirepass 111111

2)从容器1的配置文件

启动从容器1的命令中挂载了配置文件在宿主机中的完整路径 /usr/local/docker/redis-cluster/redis6-1/7012/conf/redis.conf。与主容器配置不同点在于bind项不同,多了 masterauth、slaveof 2项配置。具体内容如下。

# port表示redis容器的端口
port 6379

# bind表示绑定主服务容器的IP, 配置的2个ip表示同时绑定了2个ip,
# bing 0.0.0.0 表示对ip没有限制
# 该项可以不配置,若配置则该项可能有所不同
bind 172.17.0.10 127.0.0.1
 
# RDB相关配置
save 900 1
save 300 10
save 60 10000
rdbcompression yes
 
# 数据目录
dir /data
 
# AOF相关配置
appendonly yes
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
 
# 密码
requirepass 111111
# 主从认证密码,否则主从不能同步(若主服务器没有密码,注释该项)
masterauth 111111

# slaveof 172.17.0.9 6379表示从服务器,172.17.0.9为主服务容器ip, 也可以使用主服务容器的别名
# 有些redis版本中没有 slaveof ,使用replicaof, 如: replicaof 172.17.0.9 6379
slaveof 172.17.0.9 6379

3)从容器2的配置文件

启动从容器2的命令中挂载了配置文件在宿主机中的完整路径 /usr/local/docker/redis-cluster/redis6-1/7013/conf/redis.conf。具体内容同从容器1的配置基本一致,唯一不同点在于bind项不同,bind 172.17.0.11 127.0.0.1,其中 172.17.0.11 表示从容器2的ip。

3、哨兵相关配置

三台容器哨兵配置一模一样,在容器中不支持vim命令(若想支持需要另行安装),所以先在宿主机上创建哨兵的配置文件,再拷贝到容器的 /etc/redis/sentinel.conf 位置。

3.1 在宿主机上创建哨兵配置文件

在宿主机的 /usr/local/docker/redis-cluster 目录下创建 sentinel.conf 文件,具体内容如下。

  • 注意:若redis设置了密码,则哨兵配置中必须有 sentinel auth-pass,否则哨兵会sdown(主观下线)
# 哨兵端口号 一定要和启动命令映射的第二个端口号一致
port 26379

# 后台启动,守护线程
daemonize yes

# pid文件路径,容器中的路径
pidfile /var/run/redis-sentinel.pid

# 日志文件路径,容器中的路径
logfile /var/log/sentinel.log

# 定义工作目录,容器中的路径
dir /tmp

# sentinel 监控的master的名字叫做mymaster, IP为172.17.0.9, 端口为6379,
#  2代表2个及以上哨兵都认为master down了,才真正认为该master已经死亡,进行选举切换
sentinel monitor mymaster 172.17.0.9 6379 2

# redis mymaster 服务的密码,如果redis设置了则哨兵中必须配置auth-pass
sentinel auth-pass mymaster 111111

# 发送心跳PING来确认master是否存活 默认30s
# 如果master在“一定时间范围(ms)”内不回应PONG 或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用了
# 如果mymaster 10秒内没有响应,则认为其主观失效
sentinel down-after-milliseconds mymaster 10000

# 如果master重新选出来后,其它slave节点能同时并行从新master同步数据的台数有多少个,显然该值越大,所有slave节点完成同步切换的整体速度越快,但如果此时正好有人在访问这些slave,可能造成读取失败,影响面会更广。最保守的设置为1,同一时间,只能有一台干这件事,这样其它slave还能继续服务,但是所有slave全部完成缓存更新同步的进程将变慢。
sentinel parallel-syncs mymaster 1

# 该参数指定一个时间段,在该时间段内没有实现故障转移成功,则会再一次发起故障转移的操作,单位毫秒
sentinel failover-timeout mymaster 180000

# 不允许使用SENTINEL SET设置notification-script和client-reconfig-script。
sentinel deny-scripts-reconfig yes

# 指定了在执行故障转移时,最多可以有多少个从Redis实例在同步新的主实例,在从Redis实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长
#sentinel parallel-syncs mymaster 1

# 哨兵自己的IP,手动设定也可自动发现,用于与其他哨兵通信
# sentinel announce-ip 172.17.0.9
# sentinel announce-port 26379

3.2 从宿主机上拷贝哨兵配置文件到3个容器

使用docker cp命令从宿主机拷贝哨兵配置文件(sentinel.conf)到3个容器(docker-redis-master、docker-redis-slave1、docker-redis-slave2)的/etc/redis/sentinel.conf位置。

# 进入/usr/local/docker/redis-cluster/目录
cd /usr/local/docker/redis-cluster/

# 拷贝sentinel.conf配置文件到3个容器的/etc/redis/sentinel.conf位置
docker cp sentinel.conf docker-redis-master:/etc/redis/sentinel.conf
docker cp sentinel.conf docker-redis-slave1:/etc/redis/sentinel.conf
docker cp sentinel.conf docker-redis-slave2:/etc/redis/sentinel.conf

image-1649047796285

3.3 分别进入3个容器查看配置文件是否正确

分别进入3个容器查看配置文件 /etc/redis/sentinel.conf 是否正确,进入容器命令:docker exec -it 容器id或容器名称 bash

# 进入主容器
docker exec -it docker-redis-master bash
# 进入从容器1
docker exec -it docker-redis-slave1 bash
# 进入从容器2
docker exec -it docker-redis-slave2 bash

# 查看配置文件
cat /etc/redis/sentinel.conf

image-1649047838202

4、启动哨兵模式

4.1 启动哨兵

启动哨兵一般有两种方式,下文通过第一种方式启动:

  • redis-sentinel /etc/redis/sentinel.conf
  • redis-server /etc/redis/sentinel.conf --sentinel

通过 docker exec -it 容器id或容器名称 bash 命令分别进入3个容器后,执行 redis-sentinel  /etc/redis/sentinel.conf 命令启动哨兵。

# 进入3个容器启动哨兵
redis-sentinel /etc/redis/sentinel.conf

# 也可以使用以下命令启动哨兵
redis-server /etc/redis/sentinel.conf --sentinel

4.2 检测哨兵

通过命令 redis-cli -p 26379 info sentinel 检测当前容器的哨兵状态(命令中的26379为容器中的哨兵端口)。

  • 返回结果中,name表示主容器哨兵名称,status=ok表示哨兵正常工作,address表示主容器redis的ip和端口,slaves=2表示有2个从节点,sentinels=3表示哨兵集群中有3个哨兵在工作(第一张图中的sentinels=1是刚开始只启动了一个哨兵时查看的状态)。

image-1649047936995

5、模拟主节点故障-实现故障转移

5.1 查看容器info replication信息

分别进入主从3个容器后,连接redis服务,若有密码需要输入 auth 你的密码,查看info replication信息。

# 进入主容器
docker exec -it docker-redis-master bash
# 进入从容器1
docker exec -it docker-redis-slave1 bash
# 进入从容器2
docker exec -it docker-redis-slave2 bash

# 查看配置文件
cat /etc/redis/sentinel.conf

# 连接redis服务, 如 redis-cli -h 172.17.0.9 -p 6379
# -h不写默认为本机,-p不写默认为6379
redis-cli

# 输入密码
auth 111111

# 查看info replication信息
info replication

主节点replication信息

image-1649048991253

从节点1和2的replication信息

image-1649049010125

5.2 关闭主容器的redis服务

在宿主机上执行命令 docker stop docker-redis-master 关闭主容器的redis服务,模拟主服务挂掉的情况

哨兵监测到主服务停掉之后,且在down-after-milliseconds设置的时间范围内(默认30秒)持续监控主服务状态。当超过时间范围后:

  1. 如果down-after-milliseconds时间后,原来主节点活过来,则不进行选举,原来主节点仍为主节点。
  2. 如果down-after-milliseconds时间后,原来主节点未恢复,会选举一个新的从节点当做主节点,当之前旧的主节点服务恢复了,会成为新的主节点的一个从节点。

image-1649049086624

  • 关闭主容器服务后,在从服务器1和2上查看查看info replication信息,可以看到主服务的状态master_link_status down,表示主服务已down掉。

5.3 30秒之后查看之前2个从服务器的info replication信息

在down-after-milliseconds设置的时间范围后(默认30秒)查看2个从服务的info replication信息,可以看到172.17.0.10仍为从节点,连接的主节点变为172.17.0.11,连接状态由down变为up;172.17.0.11由slave变为master主节点,172.17.0.10做为它的从节点。

至此可以看出,哨兵已经起了作用,重新选举了主节点服务。

image-1649049125909

5.4 重新启动原先的主节点服务(docker-redis-master)

原来的主节点服务docker-redis-master已经停用,现在通过start命令重新启动。因为主节点已经变更为docker-redis-slave2(172.17.0.11),所以先修改docker-redis-master对应的配置文件后才能启动服务。

1)修改docker-redis-master的配置文件

修改 /usr/local/docker/redis-cluster/redis6-1/7011/conf/redis.conf (docker-redis-master的配置文件),添加 masterauth、slaveof 参数。

# 主从认证密码,否则主从不能同步(若主服务器没有密码,注释该项)
masterauth 111111

# 因为主服务节点变为172.17.0.11 6379
# 有些redis版本中没有 slaveof ,使用replicaof, 如: replicaof 172.17.0.11 6379
slaveof 172.17.0.11 6379

image-1649049171395

2)启动docker-redis-master服务

image-1649049179120

3)查看3个节点的info replication信息

启动docker-redis-master服务,等待30秒后,查看3个节点的info replication信息。可以看到重启后的9服务器变为从节点,10服务器仍为从节点,11服务器仍然为主节点,其从节点多了服务器9。

image-1649049195777

5.5 重新启动原先的主节点(docker-redis-master)的哨兵服务

使用docker stop 主节点的容器名,除了把主节点的redis服务停掉了之外,主节点的哨兵也挂了,当使用docker start启动容器后,当之前旧的主节点服务恢复了,会成为新的主节点的一个从节点,但是26379端口的哨兵服务没有启动,需要手动使用 redis-sentinel /etc/redis/sentinel.conf 命令启用哨兵模式。

  • 哨兵服务的配置文件中监听的主节点也是旧的,这个时候恢复它的服务会自动修改哨兵服务监听主节点的。

在docker-redis-master容器中使用 redis-cli -p 26379 info sentinel 查看哨兵信息,显示无法连接。使用命令重启哨兵服务。

# 检测哨兵
redis-cli -p 26379 info sentinel

# 启用哨兵
redis-sentinel /etc/redis/sentinel.conf

# 再次检测哨兵
redis-cli -p 26379 info sentinel

image-1649049257898

到此就搭建成了一个1主2从3哨兵的redis docker服务器。

6、常用命令

6.1 日志查看

docker logs 容器id或名称

image-1649049310547

6.2 进入/退出容器

# 进入容器
docker exec -it docker-redis-master bash 

# 进入容器后连接redis服务, -hb不写默认为本机,-p不写默认端口为6379
redis-cli -h ip -p port

# 退出容器
在容器中按ctrl+p,再按ctrl+q可从容器(也可以用exit命令)退出,并保持容器继续运行。

6.3 docker容器中更新依赖以及安装vim、ps命令

进入redis docker容器:docker exec -it 容器id/容器名称 /bin/bash,依次执行更新依赖、安装vim、安装ps的命令:

# 进入容器
docker exec -it docker-redis-master bash

# 更新依赖命令
apt-get update

# 安装vim命令
apt-get install -y vim

# 安装ps命令
apt-get install -y procps
0

评论区