Docker搭建redis集群
在《Redis的三种集群模式》这篇文章中,我们初步认识了redis三种不同的集群模式,接下来这篇文章,我们再通过实际部署搭建来对它们进行进一步的学习和了解。
一、主从复制模式
前提条件
这里准备了三台虚拟主机:192.168.205.10、192.168.205.11、192.168.205.12
- 三台主机均安装好centos7系统
- 三台主机均安装好docker并启动docker(我这里安装的docker版本为20.10.7)
- 三台主机拉取redis镜像(我这里使用redis6.2.2版本,并将镜像推送到了私有仓库)
1、三台主机都要进行的操作
1)创建存放redis.conf文件的目录
mkdir -p /root/hxq/redis
2)拉取redis配置文件
确定系统下是否安装wget命令,如果没有,则执行安装命令:yum -y install wget
执行命令:
cd /root/hxq/redis
wget -c http://download.redis.io/redis-stable/redis.conf
3)启动redis容器
docker run --name redis -v /root/hxq/redis/redis.conf:/usr/local/etc/redis/redis.conf -d -p 6379:6379 192.168.205.10:5000/redis:6.2.2
说明:
-p 端口映射,6379是redis端口
192.168.205.10:5000/redis:6.2.2为镜像名称
2、进入三台主机redis容器内部
1)进入redis容器: docker exec -it 容器id/容器名称 /bin/bash
2)进入redis客户端:redis-cli
3)查询当前主机redis的信息
执行命令:info replication
我们发现三台都是主节点
3、手动绑定主节点
说明:这里以192.168.205.10为主节点,192.168.205.11和192.168.205.12为从节点
1)分布进入11和12主机上的redis容器内部,进入redis客户端
执行命令:redis-cli
2)绑定主redis信息:SLAVEOF 主ip 主端口
执行命令:SLAVEOF 192.168.205.10 6379
3)info 查询节点信息
我们再进入10服务器,查看节点信息:
至此,redis主从已经搭建完毕
4、测试主从复制
1)测试读写数据
主节点写入数据
从节点同步数据
从节点没有写入权限
由此我们可以看出,主可以读写,从只能读。这也是redis集群的特点:读写分离。
2)客户端连接
建议用主节点连接就可以了,因为可以读写。用从节点只能读取数据。
另外,我们可以进一步认识到主从复制的缺点:
1)不具备自动容错与恢复功能,master或slave的宕机都可能导致客户端请求失败,需要等待机器重启或手动切换客户端IP才能恢复
2)难以支持在线扩容,Redis的容量受限于单机配置
二、哨兵模式(Sentinel)
在redis主从复制基础上搭建redis哨兵模式
1、配置文件
有两种方式创建sentinel.conf:
1)通过wget命令获取sentinel的配置文件
wget http://download.redis.io/redis-stable/sentinel.conf
然后再根据实际情况进行修改
2)手动创建
cd /root/hxq/redis-sentinel
vim sentinel.conf
1 port 26379 2 3 daemonize yes 4 5 logfile "/var/log/redis/sentinel.log" 6 7 # 监控名为redis-master集群;其主节点信息为【192.168.205.10:6379】;当发生意外时,至少有两个节点同意,这里的2为quorum,投票数 8 9 sentinel monitor redis-master 192.168.205.10 6379 2 10 11 # 监控认为超过5S还没响应,就认为redis-master集群挂了 12 13 sentinel down-after-milliseconds redis-master 5000 14 15 # 对sentinel集群暴露自己的ip和端口 16 17 sentinel announce-ip 192.168.205.10 18 19 sentinel announce-port 26379
2、运行哨兵
docker run -it --name sentinel -p 26379:26379 -v /root/hxq/redis-sentinel/sentinel.conf:/usr/local/etc/redis/sentinel.conf -d redis镜像名称 bash
1)进入容器
docker exec -it sentinel bash
2)创建日志目录和文件
mkdir /var/log/redis
touch /var/log/redis/sentinel.log
3)启动哨兵
redis-sentinel /usr/local/etc/redis/sentinel.conf
4)查看日志:
cat /var/log/redis/sentinel.log
在另外两台机器上按照同样的方法在一个容器中运行sentinel,配置文件有所不同:
# 对sentinel集群暴露自己的ip和端口
sentinel announce-ip ip地址
说明:这里的ip地址为sentinel所在服务器的ip地址,因为这里使用docker启动容器,如果不给定ip地址的话,就会默认使用docker分配的ip地址,就会出现问题
3、进入sentinel客户端
redis-cli -p 26379
执行命令,查看哨兵节点的信息:info sentinel
4、验证failover(故障转移)
为了验证哨兵机制下的自动主从切换,我们将主服务器192.168.205.10上的redis容器先停掉
执行命令:docker stop redis
Sentinel包括两个重要的术语:主观下线和客观下线
主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。
客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。
5、sentinel服务日志说明
Sentinel服务启动后会打印一些相关日志信息,以下是相关日志特殊字符说明:
1 +reset-master :主服务器已被重置。 2 3 +slave :一个新的从服务器已经被 Sentinel 识别并关联。 4 5 +failover-state-reconf-slaves :故障转移状态切换到了reconf-slaves 状态。 6 7 +failover-detected :另一个 Sentinel 开始了一次故障转移操作,或者一个从服务器转换成了主服务器。 8 9 +slave-reconf-sent :领头(leader)的 Sentinel 向实例发送了 SLAVEOF 命令,为实例设置新的主服务器。 10 11 +slave-reconf-inprog :实例正在将自己设置为指定主服务器的从服务器,但相应的同步过程仍未完成。 12 13 +slave-reconf-done :从服务器已经成功完成对新主服务器的同步。 14 15 -dup-sentinel :对给定主服务器进行监视的一个或多个 Sentinel 已经因为重复出现而被移除 —— 当 Sentinel 实例重启的时候,就会出现这种情况。 16 17 +sentinel :一个监视给定主服务器的新 Sentinel 已经被识别并添加。 18 19 +sdown :给定的实例现在处于主观下线状态。 20 21 -sdown :给定的实例已经不再处于主观下线状态。 22 23 +odown :给定的实例现在处于客观下线状态。 24 25 -odown :给定的实例已经不再处于客观下线状态。 26 27 +new-epoch :当前的纪元(epoch)已经被更新。 28 29 +try-failover :一个新的故障迁移操作正在执行中,等待被大多数 Sentinel 选中(waiting to be elected by themajority)。 30 31 +elected-leader :赢得指定纪元的选举,可以进行故障迁移操作了。 32 33 +failover-state-select-slave :故障转移操作现在处于select-slave 状态 —— Sentinel 正在寻找可以升级为主服务器的从服务器。 34 35 no-good-slave :Sentinel 操作未能找到适合进行升级的从服务器。Sentinel 会在一段时间之后再次尝试寻找合适的从服务器来进行升级,又或者直接放弃执行故障转移操作。 36 37 selected-slave :Sentinel 顺利找到适合进行升级的从服务器。 38 39 failover-state-send-slaveof-noone :Sentinel 正在将指定的从服务器升级为主服务器,等待升级功能完成。 40 41 failover-end-for-timeout :故障转移因为超时而中止,不过最终所有从服务器都会开始复制新的主服务器(slaves will eventually be configured to replicate with the newmaster anyway)。 42 43 failover-end :故障转移操作顺利完成。所有从服务器都开始复制新的主服务器了。 44 45 +switch-master :配置变更,主服务器的 IP 和地址已经改变。 这是绝大多数外部用户都关心的信息。 46 47 +tilt :进入 tilt 模式。 48 49 -tilt :退出 tilt 模式。
三、Redis Cluster集群
单机部署
1、创建网络
1)为什么需要创建网络?
因为默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。说简单点就是为了让容器可以直接通过容器名称进行通信。
从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称进行通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。
但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。通过 docker network create 命令可以创建自定义网络模式,默认为 bridge 网桥/桥接模式,完整命令如下:
docker network create redis-net
2)查看网络模式
执行命令:docker network ls
3)查看网络的详细信息
执行命令:docker network inspect redis-net
2、编写Redis配置文件
cd /root/hxq/redis-cluster
vim redis-cluster.tmpl
redis-cluster.tmpl 文件内容如下:
1 port ${PORT} 2 3 requirepass 1234 4 5 masterauth 1234 6 7 protected-mode no 8 9 daemonize no 10 11 appendonly yes 12 13 cluster-enabled yes 14 15 cluster-config-file nodes.conf 16 17 cluster-node-timeout 15000 18 19 cluster-announce-ip 192.168.205.10 20 21 cluster-announce-port ${PORT} 22 23 cluster-announce-bus-port 1${PORT}
1)相关配置参数说明
2)每个Redis集群节点都需要打开两个TCP连接
一个用于为客户端提供服务的正常 Redis TCP 端口,例如 6379。还有一个基于 6379 端口加 10000 的端口,比如 16379。
第二个端口用于集群总线,这是一个使用二进制协议的节点到节点通信通道。节点使用集群总线进行故障检测、配置更新、故障转移授权等等。客户端永远不要尝试与集群总线端口通信,与正常的 Redis 命令端口通信即可,但是请确保防火墙中的这两个端口都已经打开,否则 Redis 集群节点将无法通信。
在 redis-cluster 目录下执行以下命令:
循环创建 8001 - 8006 相关的目录及文件
1 for port in `seq 8001 8006`; do 2 3 mkdir -p ${port}/conf 4 5 && PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf 6 7 && mkdir -p ${port}/data; 8 9 done
查看命令执行结果,如果没有 tree 命令先安装 :yum install -y tree
执行命令:tree /root/hxq/redis-cluster/
查看每个节点的配置文件详细信息
cat /root/hxq/redis-cluster/800{1..6}/conf/redis.conf
1 port 8001 2 requirepass 1234 3 masterauth 1234 4 protected-mode no 5 daemonize no 6 appendonly yes 7 cluster-enabled yes 8 cluster-config-file nodes.conf 9 cluster-node-timeout 15000 10 cluster-announce-ip 192.168.205.10 11 cluster-announce-port 8001 12 cluster-announce-bus-port 18001 13 port 8002 14 requirepass 1234 15 masterauth 1234 16 protected-mode no 17 daemonize no 18 appendonly yes 19 cluster-enabled yes 20 cluster-config-file nodes.conf 21 cluster-node-timeout 15000 22 cluster-announce-ip 192.168.205.10 23 cluster-announce-port 8002 24 cluster-announce-bus-port 18002 25 port 8003 26 requirepass 1234 27 masterauth 1234 28 protected-mode no 29 daemonize no 30 appendonly yes 31 cluster-enabled yes 32 cluster-config-file nodes.conf 33 cluster-node-timeout 15000 34 cluster-announce-ip 192.168.205.10 35 cluster-announce-port 8003 36 cluster-announce-bus-port 18003 37 port 8004 38 requirepass 1234 39 masterauth 1234 40 protected-mode no 41 daemonize no 42 appendonly yes 43 cluster-enabled yes 44 cluster-config-file nodes.conf 45 cluster-node-timeout 15000 46 cluster-announce-ip 192.168.205.10 47 cluster-announce-port 8004 48 cluster-announce-bus-port 18004 49 port 8005 50 requirepass 1234 51 masterauth 1234 52 protected-mode no 53 daemonize no 54 appendonly yes 55 cluster-enabled yes 56 cluster-config-file nodes.conf 57 cluster-node-timeout 15000 58 cluster-announce-ip 192.168.205.10 59 cluster-announce-port 8005 60 cluster-announce-bus-port 18005 61 port 8006 62 requirepass 1234 63 masterauth 1234 64 protected-mode no 65 daemonize no 66 appendonly yes 67 cluster-enabled yes 68 cluster-config-file nodes.conf 69 cluster-node-timeout 15000 70 cluster-announce-ip 192.168.205.10 71 cluster-announce-port 8006 72 cluster-announce-bus-port 18006
3、创建redis容器
1)创建容器
将宿主机的 8001 ~ 8006 之间的端口与 6 个 Redis 容器映射,并将宿主机的目录与容器内的目录进行映射(目录挂载)。记得指定网络模式,使用我们自己创建的 redis-net 网络。
1 for port in $(seq 8001 8006); do 2 3 docker run -di -p ${port}:${port} -p 1${port}:1${port} 4 5 --restart always --name redis-${port} --net redis-net 6 7 -v /root/hxq/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf 8 9 -v /root/hxq/redis-cluster/${port}/data:/data 10 11 192.168.205.10:5000/redis:6.2.2 redis-server /usr/local/etc/redis/redis.conf; 12 13 done
创建如下图:
查看容器是否创建成功
执行命令: docker ps -n 6
查看给每个节点分配的IP信息
docker network inspect redis-net | grep -i -E "name|ipv4address"
4、创建 Redis Cluster集群
1)进入容器
docker exec -it redis-8001 bash
2)切换至指定目录
cd /usr/local/bin/
3)执行命令,创建集群
redis-cli -a 1234 --cluster create 172.19.0.2:8001 172.19.0.3:8002 172.19.0.4:8003 172.19.0.5:8004 172.19.0.6:8005 172.19.0.7:8006 --cluster-replicas 1
说明:命令中的--cluster-replicas 代表主从节点的比例,这里因为是3主3从,所以参数为1
创建过程,如下图:
至此一个高可用的 Redis Cluster 集群搭建完成,如下图所示,该集群中包含 6 个 Redis 节点,3 主 3 从。三个主节点会分配槽,处理客户端的命令请求,而从节点可用在主节点故障后,顶替主节点。
4)检查集群状态
# 使用IP
redis-cli -a 1234 --cluster check 192.168.205.10:8001
# 使用容器名称(推荐这种方式)
redis-cli -a 1234 --cluster check redis-8001:8001
5)查看集群信息和节点信息
随便进入一个容器节点,然后 cd /usr/local/bin
# 连接至集群某个节点
redis-cli -c -a 1234 -h redis-8003 -p 8003
# 查看集群信息
cluster info
#查看集群结点信息
cluster nodes
如下图:
6)SET/GET操作
说明:在 Redis Cluster 集群模式中,无论连接哪个节点,每次我们执行写入或者读取操作的时候,所有的键会根据哈希函数运算并映射到 0 ~ 16383 整数槽内,如果恰好对应的槽就在你当前连接的节点中,则直接执行命令,否则重定向至对应节点执行命令。
7)计算键属于那个槽
计算公式:slot = CRC16(key) & 16383
执行命令: cluster keyslot "name"
5、客户端连接
最后测试下客户端连接操作,随便哪个节点,看看可否通过外部访问 Redis Cluster 集群。
至此使用多个容器搭建 Redis Cluster 集群环境就到这里。
多机环境
为了让环境更加真实,我们再用多机环境来部署一遍:
192.168.10.11
192.168.10.12
整体搭建步骤还是分为4步:
- 下载 Redis 镜像(其实这步可以省略,因为创建容器时,如果本地镜像不存在,就会去远程拉取)
- 编写 Redis 配置文件
- 创建 Redis 容器
- 创建 Redis Cluster 集群
由于在多机环境与单机环境下部署都很相似,为了让文章篇幅显得不那么冗余,这里只提出与单机部署上有区别的地方。
1、网络
按照 Redis 官网的提示,为了使 Docker 与 Redis Cluster 兼容,您需要使用 Docker 的 host 网络模式。
host 网络模式需要在创建容器时通过参数 --net host 或者 --network host 指定,host 网络模式可以让容器共享宿主机网络栈,容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。所以这里不需要自定义网络,在后面创建容器的时候,--net参数需指定为host。
2、配置文件
cd /root/hxq/redis-cluster
vi redis-cluster.tmpl
11机器和12机器上面的配置有所不同:
192.168.205.11服务器上面的redis-cluster.tmpl:
port ${PORT} requirepass 1234 masterauth 1234 protected-mode no daemonize no appendonly yes cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 cluster-announce-ip 192.168.205.11 cluster-announce-port ${PORT} cluster-announce-bus-port 1${PORT}
192.168.205.12服务器上面的redis-cluster.tmpl:
1 port ${PORT} 2 requirepass 1234 3 masterauth 1234 4 protected-mode no 5 daemonize no 6 appendonly yes 7 cluster-enabled yes 8 cluster-config-file nodes.conf 9 cluster-node-timeout 15000 10 cluster-announce-ip 192.168.205.12 11 cluster-announce-port ${PORT} 12 cluster-announce-bus-port 1${PORT}
3、创建配置文件和目录
1)循环创建相关的目录及文件
cd /root/hxq/redis-cluster
11服务器:
1 for port in `seq 8001 8003`; do 2 3 mkdir -p ${port}/conf 4 5 && PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf 6 7 && mkdir -p ${port}/data; 8 9 done
12服务器:
1 for port in `seq 8004 8006`; do 2 3 mkdir -p ${port}/conf 4 5 && PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf 6 7 && mkdir -p ${port}/data; 8 9 done
2)查看配置文件
如果未安装tree命令,则执行:yum install -y tree
tree /root/hxq/redis-cluster
11服务器:cat /root/hxq/redis-cluster/800{1..3}/conf/redis.conf
12服务器:cat /root/hxq/redis-cluster/800{4..6}/conf/redis.conf
4、创建Redis容器
11服务器上面,创建容器:
1 for port in $(seq 8001 8003); do 2 3 docker run -di --restart always --name redis-${port} --net host 4 5 -v /root/hxq/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf 6 7 -v /root/hxq/redis-cluster/${port}/data:/data 8 9 192.168.205.10:5000/redis:6.2.2 redis-server /usr/local/etc/redis/redis.conf; 10 11 done
12服务器上面,创建容器:
1 for port in $(seq 8004 8006); do 2 3 docker run -di --restart always --name redis-${port} --net host 4 5 -v /root/hxq/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf 6 7 -v /root/hxq/redis-cluster/${port}/data:/data 8 9 192.168.205.10:5000/redis:6.2.2 redis-server /usr/local/etc/redis/redis.conf; 10 11 done
查看容器是否创建成功:docker ps -n 3
注意:这里创建容器时,指定--net为host
5、创建 Redis Cluster 集群
1)随便进入一个容器节点,并进入 /usr/local/bin/ 目录
docker exec -it redis-8001 bash
cd /usr/local/bin/
2)创建集群
redis-cli -a 1234 --cluster create 192.168.205.11:8001 192.168.205.11:8002 192.168.205.11:8003 192.168.205.12:8004 192.168.205.12:8005 192.168.205.12:8006 --cluster-replicas 1
6、连接至集群某个节点
redis-cli -c -a 1234 -h 192.168.205.11 -p 8001
注意:因为使用host模式,这个地方-h参数 应该取宿主机ip地址
至此一个高可用的 Redis Cluster 集群搭建完成。
参考链接:
https://cloud.tencent.com/developer/article/1474195
https://juejin.cn/post/6844903908398071815
https://juejin.cn/post/6868814738751488008
https://cloud.tencent.com/developer/news/688466