使用Docker搭建Redis哨兵
Replication
- Redis 的Replication功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器(Master),而通过复制创建出来的复制品则为从服务器(Slave)。 只要主从服务器之间的网络连接正常,主服务器就会将写入自己的数据同步更新给从服务器,从而保证主从服务器的数据相同。
- 在这种模式下,数据的复制是单向的,只能由主节点到从节点,简单理解就是从节点只支持读操作,不允许写操作。主要是读高并发的场景下用主从架构。如果主节点执行过save命令,那么在主节点挂掉的情况下也可以在从节点中读取内容。
- 当主数据库遇到异常中断服务后,开发者需要通过手动的方式选择一个从数据库来升格为主数据库,以使得系统能够继续提供服务。然而整个过程相对麻烦且需要人工介入,难以实现自动化。
使用docker-compose搭建Replication
使用一主两从的结构,考虑到后续加入哨兵,推荐使用docker network 的host方式,以方便客户端访问,主服务器使用6379端口,从服务器分别使用6380和6381端口,结构如下图:
- 下载配置文件:官方配置文件
主要设置以下几项:
#注释掉,限制redis只能本地访问
bind 127.0.0.1
#默认yes,限制为本地访问, 改为no
protected-mode no
#访问端口,默认6379
port 6379
#输入本地redis数据库存放文件夹(可选)
dir ./
#以AOF方式redis持久化(可选)
appendonly yes
#访问密码,建议设置
requirepass ****
因为每个Redis实例对外的端口都不一样,因此为每一个Redis实例都配备一个redis.conf,除port外其余都相同即可。
- 编写docker-compose.yml
version: "3.7"
services:
redis_master:
image: redis
container_name: redis_master
network_mode: "host"
volumes:
- ./config/redis.conf:/etc/redis/redis.conf
- ./data:/data
command: redis-server /etc/redis/redis.conf --requirepass YOURPASS --appendonly no
redis_slave1:
image: redis
container_name: redis_slave1
network_mode: "host"
volumes:
- ./config/redis2.conf:/etc/redis/redis.conf
- ./data:/data
command: redis-server /etc/redis/redis.conf --slaveof 宿主机IP 6379 --masterauth YOURPASS --appendonly yes
redis_slave2:
image: redis
container_name: redis_slave2
network_mode: "host"
volumes:
- ./config/redis3.conf:/etc/redis/redis.conf
- ./data:/data
command: redis-server /etc/redis/redis.conf --slaveof 宿主机IP 6379 --masterauth YOURPASS --appendonly yes
- 启动docker容器
在docker-compose.yml文件目录下执行
docker-compose up -d
查看Replication信息
docker exec -it redis_master redis-cli
如下显示则配置Replication成功
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=********,port=6380,state=online,offset=14,lag=1
slave1:ip=********,port=6381,state=online,offset=14,lag=1
master_failover_state:no-failover
master_replid:940d1ccd310a93815a992766418eafaf3949f484
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:28
哨兵 Sentinel
哨兵的作用就是监控Redis系统的运行状况,它的功能包括以下两个:
(1)监控主数据库和从数据库是否正常运行。
(2)主数据库出现故障时自动将从数据库转换为主数据库。
一个主从系统中可以有多个哨兵同时监视整个系统,哨兵之间也会互相监视。
哨兵启动后,会与要监控的主数据库建立两条连接,这两个连接的建立方式与普通的Redis客户端无异。其中一条连接用来订阅该主数据的__sentinel__:hello频道以获取其他同样监控该数据库的哨兵节点的信息,另外哨兵也需要定期向主数据库发送 INFO 等命令来获取主数据库本身的信息,因为4.4.4节介绍过当客户端的连接进入订阅模式时就不能再执行其他命令了,所以这时哨兵会使用另外一条连接来发送这些命令。
和主数据库的连接建立完成后,哨兵会定时执行下面3个操作。
- 每10秒哨兵会向主数据库和从数据库发送INFO命令。使得哨兵可以获得当前数据库的相关信息(包括运行ID、复制信息等)从而实现新节点的自动发现.
- 每 2 秒哨兵会向主数据库和从数据库的__sentinel__:hello 频道发送自己的信息。与同样监控该数据库的哨兵分享自己的信息。发送的消息内容为:<哨兵的地址>, <哨兵的端口>, <哨兵的运行 ID>, <哨兵的配臵版本>, <主数据库的名字>, <主数据库的地址>, <主数据库的端口>, <主数据库的配臵版本>
- 每1秒哨兵会向主数据库、从数据库和其他哨兵节点发送PING命令。
当超过down-after-milliseconds选项指定时间后,如果被PING的数据库或节点仍然未进行回复,则哨兵认为其主观下线(subjectively down)。主观下线表示从当前的哨兵进程看来,该节点已经下线。如果该节点是主数据库,则哨兵会进一步判断是否需要对其进行故障恢复:哨兵发送 SENTINEL is-master-down-by -addr命令询问其他哨兵节点以了解他们是否也认为该主数据库主观下线,如果达到指定数量时,哨兵会认为其客观下线(objectivelydown),并选举领头的哨兵节点对主从系统发起故障恢复。这个指定数量即为前文介绍的quorum参数。
使用docker-compose搭建哨兵
这一步将设置三个哨兵,每个哨兵监测只监测主节点,结构如下图:
- 编写配置文件sentinel.conf
port 26379
dir /tmp
sentinel monitor mymaster IP 6379 2
sentinel auth-pass mymaster 6379091170
sentinel down-after-milliseconds mymaster 10000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000
sentinel deny-scripts-reconfig yes
三个哨兵节点的配置相同
2. 编写docker-compose文件
version: '3.7'
services:
sentinel1:
image: redis
container_name: redis_sentinel_1
networks:
- redis
ports:
- "26379:26379"
volumes:
- ./config/sentinel.conf:/usr/local/etc/redis/sentinel.conf
# redis sentinel会修改config文件,修改方式推测是创建新的文件进行替代,如果只是用volumes方式挂载的话会出现Device or resource busy,无法修改
command:
- sh
- -c
- |
mkdir /etc/redis/
cp /usr/local/etc/redis/sentinel.conf /etc/redis/sentinel.conf
redis-sentinel /etc/redis/sentinel.conf
sentinel2:
image: redis
container_name: redis_sentinel_2
networks:
- redis
ports:
- "26380:26379"
command:
- sh
- -c
- |
mkdir /etc/redis/
cp /usr/local/etc/redis/sentinel.conf /etc/redis/sentinel.conf
redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./config/sentinel2.conf:/usr/local/etc/redis/sentinel.conf
sentinel3:
image: redis
container_name: redis_sentinel_3
networks:
- redis
ports:
- "26381:26379"
command:
- sh
- -c
- |
mkdir /etc/redis/
cp /usr/local/etc/redis/sentinel.conf /etc/redis/sentinel.conf
redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./config/sentinel3.conf:/usr/local/etc/redis/sentinel.conf
networks:
redis:
driver: bridge
name: redis
- 启动容器
docker-compose -f redis-sentinel.yml up -d
查看结果:
root@bfaa11ab2fda:/data# redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=IP:6379,slaves=2,sentinels=3
- 验证
关闭主节点所在容器:
docker stop redis_master
进入哨兵节点查看:
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=IP:6381,slaves=2,sentinels=3
成功将从节点升级为主节点。
5. 原理
可以进入主节点,查看__sentinel__:hello的内容:
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "__sentinel__:hello"
3) (integer) 1
1) "message"
2) "__sentinel__:hello"
3) "172.23.0.4,26379,a8a10d765844d75e02a01e615465b014fe24f369,0,mymaster,IP,6381,0"
1) "message"
2) "__sentinel__:hello"
3) "172.23.0.3,26379,c083b8f532a31f60202dd99dae8f2a38e12e6b0e,0,mymaster,IP,6381,0"
1) "message"
2) "__sentinel__:hello"
3) "172.23.0.2,26379,5171cc8406e46aea8ef8ac8be2513bb6a3ed5f6a,0,mymaster,IP,6381,0"
可以看到,发送的消息内容为:<哨兵的地址>, <哨兵的端口>, <哨兵的运行 ID>, <哨兵的配臵版本>, <主数据库的名字>, <主数据库的地址>, <主数据库的端口>, <主数据库的配臵版本>。
进入哨兵节点,查看配置文件sentinel.conf:
root@bfaa11ab2fda:/data# cat /etc/redis/sentinel.conf
port 26379
dir "/tmp"
sentinel monitor mymaster IP 6381 2
sentinel auth-pass mymaster 6379091170
sentinel down-after-milliseconds mymaster 10000
sentinel failover-timeout mymaster 10000
sentinel deny-scripts-reconfig yes
# Generated by CONFIG REWRITE
user default on nopass ~* &* +@all
sentinel myid 14d8e55124f6544c34fe07677ed631ad84a2dda8
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
sentinel current-epoch 1
sentinel known-replica mymaster IP 6379
sentinel known-replica mymaster IP 6380
sentinel known-sentinel mymaster 172.23.0.3 26379 b3dbb7b056757c6aa987af96982c933c33368783
sentinel known-sentinel mymaster 172.23.0.2 26379 bc166fe18ca1b4d4f6d1ff4663da7321a81f1bcd
在进行了一次选举之后,配置文件中的主节点成为了6381端口的Redis实例。客户端将通过该文件中记录的信息来连接redis主节点,若使用docker的内部网络,此时的IP地址都为172.23.0.*,客户端将无法访问docker的内部网络。
SpringBoot中配置Redis哨兵
spring:
redis:
sentinel:
master: mymaster
nodes:
- IP:26379
- IP:26380
- IP:26381
结语
至此,Redis哨兵搭建完毕,对客户端来说实现了读高并发下的高可用。当主节点宕机之后,哨兵将自动选举出新的主节点,而客户端无需做任何修改。
参考
docker安装redis并以配置文件方式启动
https://github.com/zaozaoniao/Redis-sentinel-with-docker-compose
《Redis入门指南(第二版)》 李子骅著