Docker搭建redis集群
这里主要介绍redis的cluster集群,其他两种集群请看最后章节
环境介绍
Docker 版本:19.03.12
Docker 版本:docker-compose version 1.24.0, build 0aa59064
Redis 版本:6.0.8
系统版本:CentOS 7.8
简介
在 Redis 3.0 版本后正式推出 Redis 集群模式,该模式是 Redis 的分布式的解决方案,是一个提供在多个 Redis 节点间共享数据的程序集,且 Redis 集群是去中心化的,它的每个 Master 节点都可以进行读写数据,每个节点都拥有平等的关系,每个节点都保持各自的数据和整个集群的状态。
Redis 集群设计的主要目的是让 Redis 数据存储能够线性扩展,通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下其可以继续处理命令。但是,如果发生较大故障(例如,大多数主站不可用时)时集群会停止运行,即 redis 集群不能保证数据的强一致性。
优势
- 高可用性: Redis 在集群模式下每个 Master 都是主从复制模式,其 Master 节点上的数据会实时同步到 Slave 节点上,当 Master 节点不可用时,其对应的 Slave 节点身份会更改为 Master 节点,保证集群的可用性
- 数据横向扩展: Redis 是一个内存数据库,所有数据都存在内存中,在单节点中所在服务器能给与的内存是有一定限制。当数据量达到一定程度后,内存将不足以支撑这么多的数据存储,这时候需要将数据进行分片存储,而 Redis 集群模式就是将数据分片存储,非常方便横向扩展。
Redis 集群的数据分片
Redis 集群没有使用一致性 Hash, 而是引入了”哈希槽”的概念。Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。
举个例子,比如当前集群有3个节点,那么:
- 节点 A 包含 0 到 5460 号哈希槽;
- 节点 B 包含 5461 到 10922 号哈希槽
- 节点 C 包含 10923 到 16383 号哈希槽;
这种结构很容易”添加”或者”删除”节点. 比如如果我想新添加个节点 D,我需要从节点 A, B, C 中得部分槽转移到节点 D 上, 如果我想移除节点 A,则需要将 A 中的槽移到 B 和 C 节点上,然后将没有任何槽的 A 节点从集群中移除即可。由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。
Redis 支持多个 key 操作,只要这些 key 在一个单个命令中执行(或者一个事务,或者 Lua 脚本执行),那么它们就属于相同的 Hash 槽。你也可以用 hash tags 命令强制多个 key 都在相同的 hash 槽中。
Redis 集群的主从复制
在 Redis 集群模式下,为了防止集群部分节点因宕机等情况造成不可用,故而 Redis 集群使用了主从复制模式。在该模式下要求 Redis 集群至少要存在六个节点,其中三个节点为主节点,能够对外提供读写。还有三个节点为从节点,会同步其对应的主节点的数据。当某个主节点出现问题不可用时,Redis 将通过选举算法从主节点对应的从节点中选择一个节点(主节点存在多个从节点的情况下),将其更改为一个新的主节点,且能够对外提供服务。
例如,在存在 A,B,C 三个主节点和其对应的 (A1、A2),(B1、B2),(C1、C2) 六个从节点,共九个节点中,如果节点 A 节点挂掉,那么其对应的从节点 A1、A2 节点将通过选举算法,选择其中一个节点提升为主节点,以确保集群能够正常服务。不过当 A1、A2 两个从节点或者或者半数以上主节点不可用时,那么集群也是不可用的
在部署 Redis 集群模式时,至少需要六个节点组成集群才能保证集群的可用性。
部署
第一种集群部署方式:使用别人已经配置好的镜像,拿来即用
这里对待部署的 Redis 集群的节点进行分配,安排如下:由于资源有限,这里共用了一台服务器,设置了六个不同的端口。
服务器ip | 端口 |
---|---|
192.168.1.130 | 7001 |
192.168.1.130 | 7002 |
192.168.1.130 | 7003 |
192.168.1.130 | 7004 |
192.168.1.130 | 7005 |
192.168.1.130 | 7006 |
创建docker-compose
文件
version: '3.3'
services:
redis1:
image: publicisworldwide/redis-cluster
network_mode: host
restart: always
environment:
- REDIS_PORT=7001
redis2:
image: publicisworldwide/redis-cluster
network_mode: host
restart: always
environment:
- REDIS_PORT=7002
redis3:
image: publicisworldwide/redis-cluster
network_mode: host
restart: always
environment:
- REDIS_PORT=7003
redis4:
image: publicisworldwide/redis-cluster
network_mode: host
restart: always
environment:
- REDIS_PORT=7004
redis5:
image: publicisworldwide/redis-cluster
network_mode: host
restart: always
environment:
- REDIS_PORT=7005
redis6:
image: publicisworldwide/redis-cluster
network_mode: host
restart: always
environment:
- REDIS_PORT=7006
启动所有redis
docker-compose up -d
查看docker版本
在文档中可查看docker版本支持的docker-compose.yml版本,为了方便大家查看,我复制出来了。不过一般来说,docker升级比较快,功能迭代也很快,最好还是用最新版本。
Compose file format | Docker Engine release |
---|---|
Compose specification | 19.03.0+ |
3.8 | 19.03.0+ |
3.7 | 18.06.0+ |
3.6 | 18.02.0+ |
3.5 | 17.12.0+ |
3.4 | 17.09.0+ |
3.3 | 17.06.0+ |
3.2 | 17.04.0+ |
3.1 | 1.13.1+ |
3.0 | 1.13.0+ |
2.4 | 17.12.0+ |
2.3 | 17.06.0+ |
2.2 | 1.13.0+ |
2.1 | 1.12.0+ |
2.0 | 1.10.0+ |
1.0 | 1.9.1.+ |
部署cluster
直接运行以下命令
docker run --rm -it inem0o/redis-trib create --replicas 1 192.168.1.130:7001 192.168.1.130:7002 192.168.1.130:7003 192.168.1.130:7004 192.168.1.130:7005 192.168.1.130:7006
会出现
Creating cluster
Performing hash slots allocation on 6 nodes…
Using 3 masters:
192.168.1.130:7001
192.168.1.130:7002
192.168.1.130:7003
Adding replica 192.168.1.130:7004 to 192.168.1.130:7001
Adding replica 192.168.1.130:7005 to 192.168.1.130:7002
Adding replica 192.168.1.130:7006 to 192.168.1.130:7003
M: 3592057f921dd65e487cd709d67487a11f7e2801 192.168.1.130:7001
slots:0-5460 (5461 slots) master
M: 60cb3e3301db04092ff1fd4301bb0292316c7d49 192.168.1.130:7002
slots:5461-10922 (5462 slots) master
M: 6a5b84956d324180d6eb8a57d959283714419a78 192.168.1.130:7003
slots:10923-16383 (5461 slots) master
S: f8a8c4f0f1413f7f98eb0b8aca219e9ffc4d62e2 192.168.1.130:7004
replicates 3592057f921dd65e487cd709d67487a11f7e2801
S: 27cedbf431c02009a9ea82fbf75eccf33b76cd7a 192.168.1.130:7005
replicates 60cb3e3301db04092ff1fd4301bb0292316c7d49
S: b2d3246317b692a22e7f016e61782fd719d87a8d 192.168.1.130:7006
replicates 6a5b84956d324180d6eb8a57d959283714419a78
Can I set the above configuration? (type ‘yes’ to accept):
输入yes
Nodes configuration updated
Assign a different config epoch to each node
Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join…
Performing Cluster Check (using node 192.168.1.130:7001)
M: 3592057f921dd65e487cd709d67487a11f7e2801 192.168.1.130:7001
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: b2d3246317b692a22e7f016e61782fd719d87a8d 192.168.1.130:7006@17006
slots: (0 slots) slave
replicates 6a5b84956d324180d6eb8a57d959283714419a78
M: 60cb3e3301db04092ff1fd4301bb0292316c7d49 192.168.1.130:7002@17002
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: f8a8c4f0f1413f7f98eb0b8aca219e9ffc4d62e2 192.168.1.130:7004@17004
slots: (0 slots) slave
replicates 3592057f921dd65e487cd709d67487a11f7e2801
S: 27cedbf431c02009a9ea82fbf75eccf33b76cd7a 192.168.1.130:7005@17005
slots: (0 slots) slave
replicates 60cb3e3301db04092ff1fd4301bb0292316c7d49
M: 6a5b84956d324180d6eb8a57d959283714419a78 192.168.1.130:7003@17003
slots:10923-16383 (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
Check for open slots…
Check slots coverage…
[OK] All 16384 slots covered.
第二种集群部署方式:自己修改配置文件
这里对待部署的 Redis 集群的节点进行分配,安排如下:由于资源有限,这里共用了一台服务器,设置了六个不同的端口。
服务器ip | 端口 |
---|---|
192.168.1.130 | 6391 |
192.168.1.130 | 6392 |
192.168.1.130 | 6393 |
192.168.1.130 | 6394 |
192.168.1.130 | 6395 |
192.168.1.130 | 6396 |
准备配置文件
根目录下新建/redis-cluster/config
文件夹,将配置文件上传到对应目录下,/redis-cluster/config
目录下上传的配置文件都会挂载到redis
容器里
配置文件目录结构:
redis-cluster/
├── config
│ ├── nodes-6391.conf #redis配置文件
│ ├── nodes-6392.conf
│ ├── nodes-6393.conf
│ ├── nodes-6394.conf
│ ├── nodes-6395.conf
│ ├── nodes-6396.conf
│ └── redis.sh #集群脚本
└── docker-compose.yml #docker-compose脚本
docker-compose.yml
version: "3"
services:
redis-master1:
image: redis:6.0.8 # 基础镜像
container_name: redis-master1 # 容器名称
working_dir: /config # 切换工作目录
environment: # 环境变量
- PORT=6391 # 会使用config/nodes-${PORT}.conf这个配置文件
ports: # 映射端口,对外提供服务
- 6391:6391 # redis的服务端口
- 16391:16391 # redis集群监控端口
stdin_open: true # 标准输入打开
tty: true # 后台运行不退出
network_mode: host # 使用host模式
privileged: true # 拥有容器内命令执行的权限
volumes:
- /redis-cluster/config:/config #配置文件目录映射到宿主机
entrypoint: # 设置服务默认的启动程序
- /bin/bash
- redis.sh
redis-master2:
image: redis:6.0.8
working_dir: /config
container_name: redis-master2
environment:
- PORT=6392
ports:
- 6392:6392
- 16392:16392
stdin_open: true
network_mode: host
tty: true
privileged: true
volumes:
- /redis-cluster/config:/config
entrypoint:
- /bin/bash
- redis.sh
redis-master3:
image: redis:6.0.8
container_name: redis-master3
working_dir: /config
environment:
- PORT=6393
ports:
- 6393:6393
- 16393:16393
stdin_open: true
network_mode: host
tty: true
privileged: true
volumes:
- /redis-cluster/config:/config
entrypoint:
- /bin/bash
- redis.sh
redis-slave1:
image: redis:6.0.8
container_name: redis-slave1
working_dir: /config
environment:
- PORT=6394
ports:
- 6394:6394
- 16394:16394
stdin_open: true
network_mode: host
tty: true
privileged: true
volumes:
- /redis-cluster/config:/config
entrypoint:
- /bin/bash
-
redis-slave2:
image: redis:6.0.8
working_dir: /config
container_name: redis-slave2
environment:
- PORT=6395
ports:
- 6395:6395
- 16395:16395
stdin_open: true
network_mode: host
tty: true
privileged: true
volumes:
- /redis-cluster/config:/config
entrypoint:
- /bin/bash
- redis.sh
redis-slave3:
image: redis:6.0.8
container_name: redis-slave3
working_dir: /config
environment:
- PORT=6396
ports:
- 6396:6396
- 16396:16396
stdin_open: true
network_mode: host
tty: true
privileged: true
volumes:
- /redis-cluster/config:/config
entrypoint:
- /bin/bash
- redis.sh
nodes-{port}.conf
#127.0.0.1修改为0.0.0.0
bind 0.0.0.0
#关闭保护模式
protected-mode no
#数据库镜像备份的文件rdb/AOF文件放置的路径修改为/data
dir "/data"
# 开启集群功能
cluster-enabled yes
# 设置运行端口
port 6391
# 设置节点超时时间,单位毫秒
cluster-node-timeout 15000
# 集群内部配置文件,每个配置修改程相应的端口
cluster-config-file nodes-6391.conf
redis.sh
上传后redis.sh
后,修改脚本权限
chmod +x /redis-cluster/config/redis.sh
redis.sh
脚本的作用是根据环境变量中的PORT
属性,以指定配置文件来启动Redis容器;
redis-server /config/nodes-${PORT}.conf
-
在
redis-cluster
目录下,使用docker-compose命令来启动所有容器docker-compose up -d
-
停止所有容器
docker-compose up
-
查看容器是否运行成功
docker ps
-
此时进入
redis-master1
容器之中,初始化Redis集群;# 进入Redis容器 docker exec -it redis-master1 /bin/bash # 初始化Redis集群命令 redis-cli --cluster create \ 192.168.1.130:6391 192.168.1.130:6392 192.168.1.130:6393 \ 192.168.1.130:6394 192.168.1.130:6395 192.168.1.130:6396 \ --cluster-replicas 1
-
集群创建过程中会让你确认配置,输入
yes
确认即可;
-
Redis集群创建成功后会输出如下信息;
-
创建成功后,在这个
redis-master1
容器里继续使用redis-cli
命令就连接到其中一个Redis服务了;# 单机模式启动 redis-cli -h 127.0.0.1 -p 6391 # 集群模式启动 redis-cli -c -h 127.0.0.1 -p 6391
-
之后通过
cluster nodes
命令可以查看节点信息,发现符合原来3主3从的预期。
SpringBoot中使用Redis集群
- 修改application.yml配置文件,添加Redis集群配置即可;
spring:
redis:
# host: 192.168.1.130 # Redis服务器地址
# database: 0 # Redis数据库索引(默认为0)
# port: 6379 # Redis服务器连接端口
password: # Redis服务器连接密码(默认为空)
timeout: 3000ms # 连接超时时间
lettuce:
pool:
max-active: 8 # 连接池最大连接数
max-idle: 8 # 连接池最大空闲连接数
min-idle: 0 # 连接池最小空闲连接数
max-wait: -1ms # 连接池最大阻塞等待时间,负值表示没有限制
cluster:
nodes:
- 192.168.1.130:6391
- 192.168.1.130:6392
- 192.168.1.130:6393
- 192.168.1.130:6394
- 192.168.1.130:6395
- 192.168.1.130:6396
常见问题
Redis 集群中的一致性
Redis 在官方文档中提及,其并不能保证数据的强一致性,即 Redis 集群在特定的条件下写入的数据可能会丢失,主要原因是因为 Redis 集群使用了异步复制模式,其写入的操作过程如下:
执行顺序如下:
- ① 客户端向任意一台主节点写入一条命令;
- ② 主节点对向客户端回复命令执行的状态;
- ③ 主节点将写操作命令传递给他的从节点;
Redis 集群对性能和一致性之间做出权衡,设置主节点在接收到客户端写命令后再将执行的命令发送到各个从节点进行同步,这个过程是异步操作,且主节点不会等待从节点回复信息就立即回复客户端命令的执行状态。这样减少同步操作,可以很大提高系统的执行速度,避免等待从节点回复消息这个过程成为系统性能的瓶颈。
然而,因为主节点不等待从节点收到信息后进行回复,就将命令的执行状态回复给了客户端,那么在节点出现问题时很可能导致出现数据丢失问题,比如客户端向主节点发送一条命令,然后主节点将该命令异步发送到它的从节点进行数据备份,然后立即回复客户端命令的执行状态。如果在这个过程中,主节点出现问导致宕机,且从节点在处理主节点发送过来的同步数据时,也发生错误。这时正好赶上主节点宕机等不可用情况,那么从节点将转换为新的主节点,在之前主节点执行的命令将丢失。
Redis 集群失败状态
在 Redis 集群模式下也不可能百分百保证集群可用性,当发生不可预知的事件导致 Redis 集群将进入失败状态,在这种状态下 Redis 集群将不能正常提供服务。其中进入失败状态的条件主要为:
- ① 全部节点都宕机,集群将进入 fail 状态;
- ② 半数以上主节点不可用,集群将进入 fail 状态;
- ③ 任意主节点挂掉,且该主节点没有对应的从节点或者从节点也全部挂掉,集群将进入 fail 状态;
Redis 集群的不足
- 不支持多数据库,只能使用 0 数据库,执行 select 0 命令;
- 键事务支持有限,当多个键分布在不同节点时无法使用事务,同一节点才能支持事务;
- 键的批量操作支持有限,比如 mset, mget 命令,如果多个键映射在不同的槽中,就不能正常使用这些命令了;
- 键是数据分区的最小粒度,不能将一个很大的键值对映射到不同的节点;
- 复制结构只支持单层结构,不支持树型结构。
其他两种集群
主从
缺点
redis通过主从复制来实现高可用,但是发生故障时需要人工进行主从切换,效率低下
部署
服务器ip:192.168.1.130
主节点:192.168.1.130:6379
从节点:192.168.1.131:6380,192.168.1.131:6381
-
运行三个redis容器
docker run --name redis-6379 -p 6379:6379 -d redis:6.0.8 docker run --name redis-6380 -p 6380:6379 -d redis:6.0.8 docker run --name redis-6381 -p 6381:6379 -d redis:6.0.8
-
redis-6380容器配置主从
#进入从节点的redis-6380容器 [root@192.168.1.131 redis-cluster]# docker exec -it redis-6380 redis-cli #使之作为从节点 127.0.0.1:6379> slaveof 192.168.1.130 6379 OK #role查看角色是否为slave 127.0.0.1:6379> role 1) "slave" 2) "192.168.1.130" 3) (integer) 6379 4) "connected" 5) (integer) 0 127.0.0.1:6379> exit
-
redis-6381容器配置主从,同上
-
测试
#进入主节点,将name的为test [root@192.168.1.130 redis-cluster]# docker exec -it redis-6379 redis-cli 127.0.0.1:6379> set name test OK 127.0.0.1:6379> exit #进入redis-6380从节点查看name是否同步过来 [root@192.168.1.131 redis-cluster]# docker exec -it redis-6380 redis-cli 127.0.0.1:6379> get name "test" 127.0.0.1:6379> exit #进入redis-6381从节点查看name是否同步过来 [root@192.168.1.131 redis-cluster]# docker exec -it redis-6381 redis-cli 127.0.0.1:6379> get name "test" 127.0.0.1:6379> exit
-
取消
redis-6381
从节点[root@192.168.1.131 redis-cluster]# docker exec -it redis-6381 redis-cli slaveof NO ONE OK [root@192.168.1.131 redis-cluster]#
哨兵
哨兵模式实现了redis主从的自动切换,提高了redis集群的可用性,提高了redis集群的故障转移效率
架构图
目录结构
/redis-sentinel
├── sentinel
│ ├── docker-compose.yml
│ ├── redis-sentinel-1.conf
│ ├── redis-sentinel-2.conf
│ └── redis-sentinel-3.conf
└── server
├── data
│ ├── redis-master
│ │ └── dump.rdb
│ ├── redis-slave-1
│ │ └── dump.rdb
│ └── redis-slave-2
│ └── dump.rdb
├── docker-compose.yml
├── redis-master.conf
├── redis-slave1.conf
└── redis-slave2.conf
Sentinel配置
sentinel的docker-compose.yml文件
---
version: '3'
services:
redis-sentinel-1:
image: redis
container_name: redis-sentinel-1
restart: always
# 为了规避Docker中端口映射可能带来的问题
# 这里选择使用host网络
network_mode: host
volumes:
- ./redis-sentinel-1.conf:/usr/local/etc/redis/redis-sentinel.conf
# 指定时区,保证容器内时间正确
environment:
TZ: "Asia/Shanghai"
sysctls:
net.core.somaxconn: '511'
command: ["redis-sentinel", "/usr/local/etc/redis/redis-sentinel.conf"]
redis-sentinel-2:
image: redis
container_name: redis-sentinel-2
restart: always
network_mode: host
volumes:
- ./redis-sentinel-2.conf:/usr/local/etc/redis/redis-sentinel.conf
environment:
TZ: "Asia/Shanghai"
sysctls:
net.core.somaxconn: '511'
command: ["redis-sentinel", "/usr/local/etc/redis/redis-sentinel.conf"]
redis-sentinel-3:
image: redis
container_name: redis-sentinel-3
restart: always
network_mode: host
volumes:
- ./redis-sentinel-3.conf:/usr/local/etc/redis/redis-sentinel.conf
environment:
TZ: "Asia/Shanghai"
sysctls:
net.core.somaxconn: '511'
command: ["redis-sentinel", "/usr/local/etc/redis/redis-sentinel.conf"]
redis-sentinel-1.conf
# bind 127.0.0.1
# 哨兵的端口号
# 因为各个哨兵节点会运行在单独的Docker容器中
# 所以无需担心端口重复使用
# 如果需要在单机
port 26379
# 设定密码认证
requirepass 123456
# 配置哨兵的监控参数
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name是为这个被监控的master起的名字
# ip是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名
# redis-port是被监控节点所监听的端口号
# quorom设定了当几个哨兵判定这个节点失效后,才认为这个节点真的失效了
sentinel monitor local-master 127.0.0.1 6379 2
# 连接主节点的密码
# 格式:sentinel auth-pass <master-name> <password>
sentinel auth-pass local-master 123456
# master在连续多长时间无法响应PING指令后,就会主观判定节点下线,默认是30秒
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds local-master 30000
redis-sentinel-2.conf
# bind 127.0.0.1
# 哨兵的端口号
# 因为各个哨兵节点会运行在单独的Docker容器中
# 所以无需担心端口重复使用
# 如果需要在单机
port 26380
# 设定密码认证
requirepass 123456
# 配置哨兵的监控参数
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name是为这个被监控的master起的名字
# ip是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名
# redis-port是被监控节点所监听的端口号
# quorom设定了当几个哨兵判定这个节点失效后,才认为这个节点真的失效了
sentinel monitor local-master 127.0.0.1 6379 2
# 连接主节点的密码
# 格式:sentinel auth-pass <master-name> <password>
sentinel auth-pass local-master 123456
# master在连续多长时间无法响应PING指令后,就会主观判定节点下线,默认是30秒
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds local-master 30000
redis-sentinel-3.conf
# bind 127.0.0.1
# 哨兵的端口号
# 因为各个哨兵节点会运行在单独的Docker容器中
# 所以无需担心端口重复使用
# 如果需要在单机
port 26381
# 设定密码认证
requirepass 123456
# 配置哨兵的监控参数
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# master-name是为这个被监控的master起的名字
# ip是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名
# redis-port是被监控节点所监听的端口号
# quorom设定了当几个哨兵判定这个节点失效后,才认为这个节点真的失效了
sentinel monitor local-master 127.0.0.1 6379 2
# 连接主节点的密码
# 格式:sentinel auth-pass <master-name> <password>
sentinel auth-pass local-master 123456
# master在连续多长时间无法响应PING指令后,就会主观判定节点下线,默认是30秒
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds local-master 30000
Redis配置
redis的docker-compose文件
---
version: '3'
services:
# 主节点的容器
redis-server-master:
image: redis
container_name: redis-server-master
restart: always
# 为了规避Docker中端口映射可能带来的问题
# 这里选择使用host网络
network_mode: host
# 指定时区,保证容器内时间正确
environment:
TZ: "Asia/Shanghai"
volumes:
# 映射配置文件和数据目录
- ./redis-master.conf:/usr/local/etc/redis/redis.conf
- ./data/redis-master:/data
sysctls:
# 必要的内核参数
net.core.somaxconn: '511'
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
# 从节点1的容器
redis-server-slave-1:
image: redis
container_name: redis-server-slave-1
restart: always
network_mode: host
depends_on:
- redis-server-master
environment:
TZ: "Asia/Shanghai"
volumes:
- ./redis-slave1.conf:/usr/local/etc/redis/redis.conf
- ./data/redis-slave-1:/data
sysctls:
net.core.somaxconn: '511'
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
# 从节点2的容器
redis-server-slave-2:
image: redis
container_name: redis-server-slave-2
restart: always
network_mode: host
depends_on:
- redis-server-master
environment:
TZ: "Asia/Shanghai"
volumes:
- ./redis-slave2.conf:/usr/local/etc/redis/redis.conf
- ./data/redis-slave-2:/data
sysctls:
net.core.somaxconn: '511'
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
redis-master.conf
# bind 127.0.0.1
# 启用保护模式
# 即在没有使用bind指令绑定具体地址时
# 或在没有设定密码时
# Redis将拒绝来自外部的连接
# protected-mode yes
# 监听端口
port 6379
# 启动时不打印logo
# 这个不重要,想看logo就打开它
always-show-logo no
# 设定密码认证
requirepass 123456
# 禁用KEYS命令
# 一方面 KEYS * 命令可以列出所有的键,会影响数据安全
# 另一方面 KEYS 命令会阻塞数据库,在数据库中存储了大量数据时,该命令会消耗很长时间
# 期间对Redis的访问也会被阻塞,而当锁释放的一瞬间,大量请求涌入Redis,会造成Redis直接崩溃
rename-command KEYS ""
# 此外还应禁止 FLUSHALL 和 FLUSHDB 命令
# 这两个命令会清空数据,并且不会失败
redis-slave1.conf
# bind 127.0.0.1
# 启用保护模式
# 即在没有使用bind指令绑定具体地址时
# 或在没有设定密码时
# Redis将拒绝来自外部的连接
# protected-mode yes
# 监听端口
port 6380
# 启动时不打印logo
# 这个不重要,想看logo就打开它
always-show-logo no
# 设定密码认证
requirepass 123456
# 禁用KEYS命令
# 一方面 KEYS * 命令可以列出所有的键,会影响数据安全
# 另一方面 KEYS 命令会阻塞数据库,在数据库中存储了大量数据时,该命令会消耗很长时间
# 期间对Redis的访问也会被阻塞,而当锁释放的一瞬间,大量请求涌入Redis,会造成Redis直接崩溃
rename-command KEYS ""
# 此外还应禁止 FLUSHALL 和 FLUSHDB 命令
# 这两个命令会清空数据,并且不会失败
# 配置master节点信息
# 格式:
#slaveof <masterip> <masterport>
# 此处masterip所指定的redis-server-master是运行master节点的容器名
# Docker容器间可以使用容器名代替实际的IP地址来通信
slaveof 127.0.0.1 6379
# 设定连接主节点所使用的密码
masterauth "123456"
redis-slave2.conf
# bind 127.0.0.1
# 启用保护模式
# 即在没有使用bind指令绑定具体地址时
# 或在没有设定密码时
# Redis将拒绝来自外部的连接
# protected-mode yes
# 监听端口
port 6381
# 启动时不打印logo
# 这个不重要,想看logo就打开它
always-show-logo no
# 设定密码认证
requirepass 123456
# 禁用KEYS命令
# 一方面 KEYS * 命令可以列出所有的键,会影响数据安全
# 另一方面 KEYS 命令会阻塞数据库,在数据库中存储了大量数据时,该命令会消耗很长时间
# 期间对Redis的访问也会被阻塞,而当锁释放的一瞬间,大量请求涌入Redis,会造成Redis直接崩溃
rename-command KEYS ""
# 此外还应禁止 FLUSHALL 和 FLUSHDB 命令
# 这两个命令会清空数据,并且不会失败
# 配置master节点信息
# 格式:
#slaveof <masterip> <masterport>
# 此处masterip所指定的redis-server-master是运行master节点的容器名
# Docker容器间可以使用容器名代替实际的IP地址来通信
slaveof 127.0.0.1 6379
# 设定连接主节点所使用的密码
masterauth "123456"
哨兵模式验证
启动redis
在/redis-sentinel/server
下执行
docker-compose up
启动sentinel
在/redis-sentinel/sentinel
下执行
docker-compose up
全部正常启动后
[root@rabbit1 server]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d468f032604a redis "docker-entrypoint.s…" 8 minutes ago Up 8 minutes redis-server-slave-2
59d4f375cafc redis "docker-entrypoint.s…" 8 minutes ago Up 8 minutes redis-server-slave-1
7850df576f57 redis "docker-entrypoint.s…" 8 minutes ago Up About a minute redis-server-master
d0b5fd7a3929 redis "docker-entrypoint.s…" 8 minutes ago Up 8 minutes redis-sentinel-3
5f475fc9bf9a redis "docker-entrypoint.s…" 8 minutes ago Up 8 minutes redis-sentinel-1
4950fa03f567 redis "docker-entrypoint.s…" 8 minutes ago Up 8 minutes redis-sentinel-2
进入主服务器查看
[root@rabbit1 server]# docker exec -it redis-server-master redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.130,port=6381,state=online,offset=21464,lag=1
slave1:ip=192.168.1.130,port=6380,state=online,offset=21464,lag=1
master_replid:98c6a6ad25de45d00520f4f1500e9522ce89a4c5
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:21464
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:21464
然后停掉主节点,查看哨兵是否正常进行选举
[root@rabbit1 server]# docker stop redis-server-master
redis-server-master
[root@rabbit1 server]# docker logs -f redis-sentinel-1
1:X 24 Feb 2021 15:18:30.895 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:X 24 Feb 2021 15:18:30.895 # Redis version=6.0.10, bits=64, commit=00000000, modified=0, pid=1, just started
1:X 24 Feb 2021 15:18:30.895 # Configuration loaded
1:X 24 Feb 2021 15:18:30.899 * Running mode=sentinel, port=26379.
1:X 24 Feb 2021 15:18:30.914 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:18:30.914 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:18:30.914 # Sentinel ID is 04282ab7ae6ca74e2ee5ac3bde57c9e5299b2e6a
1:X 24 Feb 2021 15:18:30.914 # +monitor master local-master 192.168.1.130 6379 quorum 2
1:X 24 Feb 2021 15:18:40.366 * +sentinel sentinel 05b83e725b0b30f3bab775b6b5aac5002c180108 192.168.1.130 26380 @ local-master 192.168.1.130 6379
1:X 24 Feb 2021 15:18:40.368 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:18:40.368 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:18:42.358 * +sentinel sentinel 1cf1c4136fe3c22b31cd3004ba8806346828a668 192.168.1.130 26381 @ local-master 192.168.1.130 6379
1:X 24 Feb 2021 15:18:42.364 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:18:42.364 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:18:50.333 * +slave slave 192.168.1.130:6381 192.168.1.130 6381 @ local-master 192.168.1.130 6379
1:X 24 Feb 2021 15:18:50.337 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:18:50.337 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:18:50.337 * +slave slave 192.168.1.130:6380 192.168.1.130 6380 @ local-master 192.168.1.130 6379
1:X 24 Feb 2021 15:18:50.338 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:18:50.338 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:21:30.519 # +sdown master local-master 192.168.1.130 6379
1:X 24 Feb 2021 15:21:30.543 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:21:30.543 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:21:30.543 # +new-epoch 1
1:X 24 Feb 2021 15:21:30.560 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:21:30.560 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:21:30.560 # +vote-for-leader 1cf1c4136fe3c22b31cd3004ba8806346828a668 1
1:X 24 Feb 2021 15:21:30.575 # +odown master local-master 192.168.1.130 6379 #quorum 3/2
1:X 24 Feb 2021 15:21:30.575 # Next failover delay: I will not start a failover before Wed Feb 24 15:27:31 2021
1:X 24 Feb 2021 15:21:31.753 # +config-update-from sentinel 1cf1c4136fe3c22b31cd3004ba8806346828a668 192.168.1.130 26381 @ local-master 192.168.1.130 6379
1:X 24 Feb 2021 15:21:31.753 # +switch-master local-master 192.168.1.130 6379 192.168.1.130 6380
1:X 24 Feb 2021 15:21:31.754 * +slave slave 192.168.1.130:6381 192.168.1.130 6381 @ local-master 192.168.1.130 6380
1:X 24 Feb 2021 15:21:31.754 * +slave slave 192.168.1.130:6379 192.168.1.130 6379 @ local-master 192.168.1.130 6380
1:X 24 Feb 2021 15:21:31.757 # Could not rename tmp config file (Device or resource busy)
1:X 24 Feb 2021 15:21:31.758 # WARNING: Sentinel was not able to save the new configuration on disk!!!: Device or resource busy
1:X 24 Feb 2021 15:22:01.795 # +sdown slave 192.168.1.130:6379 192.168.1.130 6379 @ local-master 192.168.1.130 6380
通过查看哨兵的日志,可看到哨兵停掉了6379这个主节点,将6380选举了新的主节点