Docker集群部署MySQL、Redis集群实例
简介

需要具备的基础
- MySQL数据库开发能力
- 了解Redis,会简单操作
- 了解Linux指令,能在Linux上安装卸载软件
哪里需要集群?

前后端分离部署图


项目Demo
- renrenfast开源前后端项目
Linux基础强化
firewalld防火墙
- centos7默认安装了firewalld防火墙
- 通过防火墙允许或限制数据的通过
管理防火墙
查看状态
firewall-cmd --state启动、关闭、重启防火墙
service firewall start
service firewall stop
service firewall restart端口管理
# 开放
firewall-cmd --permanent --add-port=8080-8085/tcp
# 重新加载防火墙配置
firewall-cmd --reload
# 关闭端口,要与之前写的add时开放的端口范围相同,不能开放多个端口,只关闭一个端口
firewall-cmd --permanent --remove-port=8080-8085/tcp查看开启的端口
firewall-cmd --permanent --list-ports查看使用网络的服务
firewall-cmd --permanent --list-services云计算中的Docker

Docker容器管理命令

Docker镜像导入导出
docker save java > /home/java.tar.gz
docker load java < /home/java.tar.gzDocker暂停 停止容器
docker pause container-name
docker unpause container-name
docker stop container-name
docker start -i container-nameMySQL集群搭建
常见MySQL集群方案

选用PXC集群方式。
PXC原理
- PXC(Percona XtraDB Cluster)

- 任何一个节点都可读可写
- 建议PXC使用Percona Server(MySQL改进版,性能提升很大)
PXC与Replication方案对比


PXC的数据强一致性
- PXC同步复制,事务在所有集群节点要么同时提交,要么不提交

- Replication采用异步复制,无法保证数据一致性

PXC集群安装
- 最新的PXC版本是PXC8.0,即对应MySQL8.0。本实验使用PXC5.7,即对应MySQL5.7,主要是因为大部分项目都采用的MySQL5.7
| 实验版本 | 最新版本 | |
|---|---|---|
| PXC | 5.7 | 8.0 |
| XtraBackup | 2.4 | 8.0 |
节点分配
物理机IP: 10.248.192.137
Docker内部网段子网掩码:172.18.0.0/24
| 节点 | docker内部IP | 映射物理机端口 |
|---|---|---|
| MySQL-node1 | 172.17.0.2 | 3306 |
| MySQL-node2 | 172.17.0.3 | 3307 |
| MySQL-node3 | 172.17.0.4 | 3308 |
| MySQL-node4 | 172.17.0.5 | 3309 |
| MySQL-node4 | 172.17.0.6 | 3310 |
| Haproxy | 172.17.0.7 | 4001 WEB看板端口<br/>4002 MySQL负载均衡入口 |
拉取Docker镜像
docker pull percona/percona-xtradb-cluster
docker image ls由于镜像的名字太长,不便于使用,我们可以在本地对镜像名称进行修改
docker tag percona/percona-xtradb-cluster pxc
docker image ls此时可以把原来的镜像删除掉
docker iamge rm percona/percona-xtradb-cluster pxc创建内部网络
- 出于安全考虑,需要给PXC集群实例创建Docker内部网络
# 创建网段
docker network create net1
# 查看网段信息
docker network inspect net1
# 删除网段
docker network rm net1- docker默认的网段是172.17.0.x
- 创建网络的时候不指定网段,会默认从dokcer默认网段向下排,例如下一个网段是172.18.0.x
- 创建指定网段
docker network create --subnet=172.18.0.0/24 net1
docker inspect net1
# 如果删除
docker network rm net1- 子网掩码172.18.0.0/24中的/24的意思是172.17.0前三位固定,最后一位动,即子网掩码为255.255.255.0,用二进制表示前面就是24位1
- 如果子网掩码是172.18.0.0/16,那么172.18固定,后面两个段动。
创建Docker卷
- 业务数据通常存在物理机里,而不是存在容器内
- PXC无法使用目录映射方式运行(启动会闪退),所以需要使用Docker卷技术
# --name可以省略不写
docker volume create --name v1
docker inspect v1
[
{
"CreatedAt": "2022-08-18T09:41:14+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/snap/docker/common/var-lib-docker/volumes/v1/_data",
"Name": "v1",
"Options": {},
"Scope": "local"
}
]
# 如果删除
docker volume rm v1volume在物理机的/var/snap/docker/common/var-lib-docker/volumes/v1/_data位置
创建PXC容器
- 向PXC镜像传入运行参数就能创建出PXC容器
- MYSQL_ROOT_PASSWORD 数据库密码,账户默认为
root - CLUSTER_NAME 集群名称
- XTRABACKUP_PASSWORD 数据库节点之间同步的密码
- --privileged:使用该参数,container内的root拥有真正的root权限
- 使用pxc镜像
- 第一个启动的PXC节点是主节点,它要初始化PXC集群
- PXC启动之后,就没有主节点角色了
- PXC集群任何一个节点都是可以读写数据的
# 第一个PXC
docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=abc123456 \
-e CLUSTER_NAME=PXC \
-e XTRABACKUP_PASSWORD=abc123456 \
-v v1:/var/lib/mysql \
--privileged \
--name=node1 \
--net=net1 --ip=172.18.0.2 \
pxc
# 创建第2、3、4、5个volume
# docker volume create --name v1 上面创建过了
docker volume create --name v2
docker volume create --name v3
docker volume create --name v4
docker volume create --name v5
# 创建其他4个节点
# 需要修改端口、挂载卷名、IP、容器名,同时增加CLUSTER_JOIN参数
# 第2个PXC
docker run -d -p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=abc123456 \
-e CLUSTER_NAME=PXC \
-e XTRABACKUP_PASSWORD=abc123456 \
-e CLUSTER_JOIN=node1 \
-v v2:/var/lib/mysql \
--privileged --name=node2 \
--net=net1 --ip=172.18.0.3 \
pxc
# 第3个PXC
docker run -d -p 3308:3306 -e CLUSTER_NAME=PXC -e MYSQL_ROOT_PASSWORD=abc123456 -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v3:/var/lib/mysql --privileged --name=node3 --net=net1 --ip=172.18.0.4 pxc
# 第4个PXC
docker run -d -p 3309:3306 -e CLUSTER_NAME=PXC -e MYSQL_ROOT_PASSWORD=abc123456 -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v4:/var/lib/mysql --privileged --name=node4 --net=net1 --ip=172.18.0.5 pxc
# 第5个PXC
docker run -d -p 3310:3306 -e CLUSTER_NAME=PXC -e MYSQL_ROOT_PASSWORD=abc123456 -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v5:/var/lib/mysql --privileged --name=node5 --net=net1 --ip=172.18.0.6 pxc- 必须主节点可以访问了,才能创建从节点,否则会闪退
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6563dac8b2ae pxc "/entrypoint.sh mysq…" 6 seconds ago Up 6 seconds 4567-4568/tcp, 33060/tcp, 0.0.0.0:3310->3306/tcp, :::3310->3306/tcp node5
17c1d1314252 pxc "/entrypoint.sh mysq…" 8 seconds ago Up 8 seconds 4567-4568/tcp, 33060/tcp, 0.0.0.0:3309->3306/tcp, :::3309->3306/tcp node4
e58f6800f23d pxc "/entrypoint.sh mysq…" 9 seconds ago Up 8 seconds 4567-4568/tcp, 33060/tcp, 0.0.0.0:3308->3306/tcp, :::3308->3306/tcp node3
45df9d0864fb pxc "/entrypoint.sh mysq…" 26 seconds ago Up 26 seconds 4567-4568/tcp, 33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp node2
893961f0c9e3 pxc "/entrypoint.sh mysq…" 14 minutes ago Up 14 minutes 4567-4568/tcp, 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp node1node2-node5闪退问题(PXC8.0)
上面的步骤操作完后,过一会儿node2-node5会闪退。本实验使用的是PXC8.0(Percona Server for MySQL 8.0),直接启动node2-5会出现MySQL无法启动的情况。查看log信息大致如下:
2022-08-18T06:24:23.078258Z 0 [ERROR] [MY-000000] [Galera] failed to open gcomm backend connection: 110: failed to reach primary view (pc.wait_prim_timeout): 110 (Connection timed out)
at gcomm/src/pc.cpp:connect():161
2022-08-18T06:24:23.078271Z 0 [ERROR] [MY-000000] [Galera] gcs/src/gcs_core.cpp:gcs_core_open():219: Failed to open backend connection: -110 (Connection timed out)
2022-08-18T06:24:24.078556Z 0 [Note] [MY-000000] [Galera] gcomm: terminating thread
2022-08-18T06:24:24.078655Z 0 [Note] [MY-000000] [Galera] gcomm: joining thread
2022-08-18T06:24:24.078865Z 0 [ERROR] [MY-000000] [Galera] gcs/src/gcs.cpp:gcs_open():1811: Failed to open channel 'PXC' at 'gcomm://node1': -110 (Connection timed out)
2022-08-18T06:24:24.078959Z 0 [ERROR] [MY-000000] [Galera] gcs connect failed: Connection timed out
2022-08-18T06:24:24.079004Z 0 [ERROR] [MY-000000] [WSREP] Provider/Node (gcomm://node1) failed to establish connection with cluster (reason: 7)
2022-08-18T06:24:24.079052Z 0 [ERROR] [MY-010119] [Server] Aborting
2022-08-18T06:24:24.079551Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.28-19.1) Percona XtraDB Cluster (GPL), Release rel19, Revision f544540, WSREP version 26.4.3.虽说报错信息和文章中的不一样,但是确实是我在参考其他资料时没有提到的一点,一个变量:pxc-encrypt-cluster-traffic上,根据官网资料,pxc-encrypt-cluster-traffic 变量默认是启用,所以要求所有节点使用相同的密钥和证书文件,MySQL生成默认密钥和证书文件,并将其放在数据目录中。这些自动生成的文件适用于自动 SSL 配置。所以将第一个节点数据目录下的 *.pem全部复制到第二个节点,再次执行systemctl start mysql命令,节点正常启动。
所以,通过docker inspect node1查看v1卷的物理路径,然后复制其证书文件到v2、v3、v4、v5卷中即可。
cp *.pem /var/snap/docker/common/var-lib-docker/volumes/v2/_data/
cp *.pem /var/snap/docker/common/var-lib-docker/volumes/v3/_data/
cp *.pem /var/snap/docker/common/var-lib-docker/volumes/v4/_data/
cp *.pem /var/snap/docker/common/var-lib-docker/volumes/v5/_data/再重启node2-node5的容器即可
docker container stop node2 node3 node4 node5
docker container start node2 node3 node4 node5数据库负载均衡
- 虽然搭建了集群,但是没有负载均衡,请求还是只会落在一个数据库上

- 使用Haproxy做负载均衡,请求会均匀分发给每个PXC节点,单节点负载低,性能好

- 负载均衡中间件对比

安装Haproxy
docker pull haproxy
docker image ls创建Haproxy配置文件
- Haproxy配置文件需要自己写
touch /home/bill/haproxy/haproxy.cfg- 配置模板
global
#工作目录
chroot /usr/local/etc/haproxy
#日志文件,使用rsyslog服务中local5日志设备(/var/log/local5),等级info
log 127.0.0.1 local5 info
#守护进程运行
daemon
defaults
log global
mode http
#日志格式
option httplog
#日志中不记录负载均衡的心跳检测记录
option dontlognull
#连接超时(毫秒)
timeout connect 5000
#客户端超时(毫秒)
timeout client 50000
#服务器超时(毫秒)
timeout server 50000
#监控界面
listen admin_stats
#监控界面的访问的IP和端口
bind 0.0.0.0:8888
#访问协议
mode http
#URI相对地址
stats uri /dbs
#统计报告格式
stats realm Global\ statistics
#登陆帐户信息
stats auth admin:abc123456
#数据库负载均衡
listen proxy-mysql
#访问的IP和端口
bind 0.0.0.0:3306
#网络协议
mode tcp
#负载均衡算法(轮询算法)
#轮询算法:roundrobin
#权重算法:static-rr
#最少连接算法:leastconn
#请求源IP算法:source
balance roundrobin
#日志格式
option tcplog
#在MySQL中创建一个没有权限的haproxy用户,密码为空。Haproxy使用这个账户对MySQL数据库心跳检测
option mysql-check user haproxy
server MySQL_1 172.18.0.2:3306 check weight 1 maxconn 2000
server MySQL_2 172.18.0.3:3306 check weight 1 maxconn 2000
server MySQL_3 172.18.0.4:3306 check weight 1 maxconn 2000
server MySQL_4 172.18.0.5:3306 check weight 1 maxconn 2000
server MySQL_5 172.18.0.6:3306 check weight 1 maxconn 2000
#使用keepalive检测死链
option tcpka - 第50-55行为心跳检测,需要在每个MySQL节点上创建一个无任何权限、无密码的haproxy用户,用来进行心跳检测
# 在node1-node5上面执行
CREATE USER 'haproxy'@'%' IDENTIFIED BY ''; # 账号为haproxy,密码为空创建Haproxy容器
- 8888是haproxy状态网页的端口
- 3306的haproxy的默认端口,由于已经被node1占用,故需要修改映射端口
- 考虑到高可用,至少2个Haproxy容器
docker run -it -d \
-p 4001:8888 -p 4002:3306 \
-v /home/bill/haproxy:/usr/local/etc/haproxy \
--name h1 --privileged --net=net1 --ip=172.18.0.7 haproxy启动之后发现闪退,查看log如下:
docker logs h1
[NOTICE] (1) : New worker (9) forked
[NOTICE] (1) : Loading success.
[NOTICE] (9) : haproxy version is 2.6.2-16a3646
[NOTICE] (9) : path to executable is /usr/local/sbin/haproxy
[ALERT] (9) : [haproxy.main()] Cannot chroot(/usr/local/etc/haproxy).
[NOTICE] (1) : haproxy version is 2.6.2-16a3646
[NOTICE] (1) : path to executable is /usr/local/sbin/haproxy
[WARNING] (1) : Current worker (9) exited with code 1 (Exit)
[ALERT] (1) : exit-on-failure: killing every processes with SIGTERM
[WARNING] (1) : All workers exited. Exiting... (1)看到有Cannot chroot(/usr/local/etc/haproxy)推测权限问题,于是以root账户运行容器(加上-u 0参数):
docker run -it -d \
-u 0 \
-p 4001:8888 -p 4002:3306 \
-v /home/bill/haproxy:/usr/local/etc/haproxy \
--name h1 --privileged --net=net1 --ip=172.18.0.7 haproxy启动成功
docker logs -f h1
[NOTICE] (1) : New worker (9) forked
[NOTICE] (1) : Loading success.访问 http://10.248.192.137:4001/dbs ,输入账号密码(admin:abc123456),界面如下:

再数据库连接工具中,输入4002端口连接:

MySQL连接成功,Haproxy启动成功
例如在H1中创建test数据库:
create database test;可以看到node1-node5节点均同步新建了test数据库:

Haproxy双机热备
- 单节点Haproxy不具备高可用,必须要有冗余设计

虚拟IP

Haproxy双机热备方案
利用Keepalived实现双机热备


安装Keepalived
- Keepalived必须安装在Haproxy所在的容器内
apt-get update
apt-get install keepalivedKeepalived配置文件
Keepalived的配置文件路径是:
/etc/keepalived/keepalived.conf- state: Keepalived的身份(MASTER主服务,BACKUP备用服务器)。主服务抢占虚拟IP,备用服务不会抢占IP
- interface: 宿主机的网卡名
- virtual_router_id: 虚拟路由ID,MASTER和BACKUP需要一致,值为0~255之间
- priority:MASTER的权重要高于BACKUP,根据硬件配置调节,数字越大优先级越高
- advert_int: 心跳检测时间间隔(秒)
- authentication: 主从服务的鉴权账户,主备服务需配置相同
- virtual_ipaddress: 虚拟IP地址。可以设置多个虚拟IP,每行一个
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
172.18.0.201
}
}- haproxy容器内默认是没有vim编辑器的,需要手动安装vim编辑器
apt-get install vim
vi /etc/keepalived/keepalived.conf启动Keepalived服务
service keepalived start在宿主机中验证配置
ping 172.18.0.201
PING 172.18.0.201 (172.18.0.201) 56(84) bytes of data.
64 字节,来自 172.18.0.201: icmp_seq=1 ttl=64 时间=0.124 毫秒
64 字节,来自 172.18.0.201: icmp_seq=2 ttl=64 时间=0.085 毫秒
64 字节,来自 172.18.0.201: icmp_seq=3 ttl=64 时间=0.088 毫秒
64 字节,来自 172.18.0.201: icmp_seq=4 ttl=64 时间=0.087 毫秒
64 字节,来自 172.18.0.201: icmp_seq=5 ttl=64 时间=0.087 毫秒
^C
--- 172.18.0.201 ping 统计 ---
已发送 5 个包, 已接收 5 个包, 0% 包丢失, 耗时 4095 毫秒
rtt min/avg/max/mdev = 0.085/0.094/0.124/0.014 ms配置MASTER节点成功。
MySQL的热备份
冷备份与热备份
冷备份
- 冷备份需要关闭数据库,在进行备份操作,通常做法是拷贝数据文件
- 冷备份是最简单最安全的一种备份方式
- 大型网站无法做到关闭业务备份数据,所以冷备份不是最佳选择
热备份
- 在系统运行的状态下去备份,也是难度最大的备份
- MySQL常见的热备份有LVM和XtraBackup两种方案
- 建议使用XtraBackup热备MySQL
XtraBackup

- 备份过程中不锁表,快速可靠
- XtraBackup备份过程中不会打断正在执行的任务(例如增删改查)
- XtraBackup能够基于压缩等功能节约磁盘空间和流量
全量备份和增量备份
- 全量备份是备份全部数据,备份过程时间长,占用空间大

- 增量备份只备份变化的那部分数据。备份时间短,占用空间小

增量备份操作步骤
这部分不要操作,只是一个踩坑的地方。往下看单独部署XtraBackup容器
先创建一个volume,用来存放备份的数据
docker volume create backup把volume映射到node1上
docker stop node1
node1节点成功关闭,下面需要把node1删掉,重新创建node1并挂载backup数据卷。由于node1的数据存储在v1卷,因此重新创建node1不影响节点的数据。
# 删除node1节点
docker container rm node1
# 创建node1
docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=abc123456 \
-e CLUSTER_NAME=PXC \
-e XTRABACKUP_PASSWORD=abc123456 \
-e CLUSTER_JOIN=node2 \
-v v1:/var/lib/mysql \
-v backup:/data \
--privileged \
--name=node1 \
--net=net1 --ip=172.18.0.2 \
pxc- 增加了
-v backup:/data,映射备份目录 - 增加了
-e CLUSTER_JOIN=node2,加入到集群内,join到node2-node5任意一个节点均可

node1节点成功启动。下一步进入到PXC容器安装XtraBackup,并执行备份:
# 需要使用root身份操作
docker exec -it -u 0 node1 bash
# PXC5.7镜像自带innobackupex
# apt-get update
# apt-get install percona-xtrabackup-24
# 全量备份
innobackupex --user=root --password=abc123456 /data/backup/full- 这里有个问题,pxc8.0的容器里没有
apt-get命令,通过离线安装包方式安装也比较麻烦,不利于自动化构建。通过查阅资料,发现一种更好的XtraBackup部署方法:https://docs.percona.com/percona-xtrabackup/8.0/installation/docker.html - 根据官网教程,如果是PXC8.0,可以单独部署一个XtraBackup容器,在启动XtraBackup容器的时候,指定需要备份的MySQL节点,挂载需要备份的MySQL的volume,相比于上面的进到PXC容器去手动安装XtraBackup,要更方便、快捷
- PXC5.7镜像自带innobackupex,不用apt安装,而且PXC5.7容器内没有apt-get
PXC全量恢复
- 数据库可以热备份,但是不能热还原。只能新建空白的MySQL节点,再进行数据恢复,再建立PXC集群
- 还原数据前要将未提交的事务回滚,还原数据之后重启MySQL
查看数据在物理机的位置
ls /var/snap/docker/common/var-lib-docker/volumes/backup/_data/backup/full/
2022-08-23_04-34-13恢复数据操作
# 删除MySQL集群及数据卷
docker container stop node1 node2 node3 node4 node5
docker container rm node1 node2 node3 node4 node5
docker volume rm v1 v2 v3 v4 v5
# 重新创建node1
docker volume create v1
docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=abc123456 \
-e CLUSTER_NAME=PXC \
-e XTRABACKUP_PASSWORD=abc123456 \
-v v1:/var/lib/mysql \
-v backup:/data \
--privileged \
--name=node1 \
--net=net1 --ip=172.18.0.2 \
pxc
# 进入到node1节点内
docker exec -it -u 0 node1 bash
# =====================================
# 清空MySQL数据
rm -rf /var/lib/mysql/*
# 未提交的事务回滚
innobackupex --user=root --password=abc123456 --apply-back /data/backup/full/2022-08-23_04-34-13
# 执行冷还原
innobackupex --user=root --password=abc123456 --copy-back /data/backup/full/2022-08-23_04-34-13
# 需要把MySQL数据权限改成mysql:mysql(默认为root:root,否则容器会重启失败)
chown -R mysql:mysql /var/lib/mysql
# 退出容器
exit
# =====================================
# 重启容器
docker container restart node1
MySQL_1节点启动成功,并且数据恢复成功(haproxy的心跳监测靠的是haproxy账号不断地去尝试登录MySQL)
PXC集群搭建-生产环境所遇问题
1. 不能映射目录,只能挂volume
path in container:
- /var/lib/mysql
- /var/log/mysql
- /backup
2. 第一个创建的节点重启会启动失败
参考CSDN:https://blog.csdn.net/qq_26896085/article/details/104547257
我的解决方案是删掉容器(不要动创建好的volume),重新创建容器并添加启动参数-e CLUSTER_JOIN=pxc02,也就是加入到一个可用节点里
3. 关于MySQL账户的恢复
MySQL账户不能单纯的通过导入mysql数据库内的user和db表解决,单纯的导入这两个表的数据,MySQL节点之间会不同步。
如果可以通过create user创建最好,可以自动同步。https://www.jb51.net/article/194392.htm
mysqlpump -uroot -proot --exclude-databases=% --users --exclude-users=mysql.session,mysql.sys,root > /backup/user.sqlRedisCluster集群
- 高速缓存利用内存保护数据,读写速度远超硬盘
- 高速缓存可以减少I/O操作,降低I/O压力
- Redis是VMware开发的开源免费KV型NoSQL缓存产品
- Redis具有良好性能,最多可以提供10万次/秒的读写
- 目前新浪微博团队组建了世界上最大的Redis集群(2018)
Redis集群介绍
- RedisCluster: 官方推荐,没有中心节点(PXC也无中心节点)
- Codis: 中间件产品,存在中心节点(360公司推出)
- Twemproxy:中间件产品,存在中心节点
使用RedisCluster
- 无中心节点,客户端与redis节点直连,不需要中间代理层
- 数据可以被分片存储(每个节点存储的数据不同)。每个节点有加冗余节点,节点故障可切换到冗余节点,保障集群正常运转
- 管理方便,后续可自行增加或删除节点

- 本实验搭建的是redis-6节点(一主一从结构)
| 编号 | IP | 对外开放端口 | redis节点名 |
|---|---|---|---|
| 1 | 172.19.0.2 | 5001 | r1 |
| 2 | 172.19.0.3 | 5002 | r2 |
| 3 | 172.19.0.4 | 5003 | r3 |
| 4 | 172.19.0.5 | 5004 | r4 |
| 5 | 172.19.0.6 | 5005 | r5 |
| 6 | 172.19.0.7 | 5006 | r6 |
- 其中salve-master结构是通过下面的redis-trib.rb脚本自动配置所得
Redis主从同步
- Redis集群中的数据库复制是通过主从同步来实现的
- 主节点(Master)把数据发送给从节点(Slave)
- 主从同步的好处在于高可用,Redis节点有冗余设计

Redis集群高可用
- Redis集群中应该包含奇数个Master,至少应该有3个Master
- Redis集群中每个Master都应该有Slave

- RedisCluster无需配置负载均衡,因为renrenfast后端已经实现了redis负载均衡
拉取redis image
包括拉取镜像、创建net2网络
# yyyyttttwwww的redis已经把配置文件修改完毕
docker pull yyyyttttwwww/redis
# 重命名
docker tag yyyyttttwwww/redis redis
docker network create --subnet=172.19.0.0/16 net2
docker run -it -d --name r1 -p 5001:6379 --net=net2 --ip=172.19.0.2 redis bash配置Redis节点
- 配置文件路径:
/usr/redis/redis.conf 重点参数详情
- daemonize yes # 以后台进程运行
- cluster-enabled yes # 开启集群
- cluster-config-file nodes.conf # 集群配置文件
- cluster-node-timeout 15000 # 超时时间
- appendonly yes # 开启AOF模式,即日志功能,redis宕机可以根据AOF的日志恢复数据
vi /usr/redis/redis.conf
# 搜索 不要进入到insert模式,直接输入/命令
/daemonize
/cluster-enabled
/cluster-config-file
/cluster-node-timeout
/appendonly
# 保存
:wq
# 运行redis
cd /usr/redis/src
./redis-server ../redis.conf首个节点搭建成功。接下来创建第2-6个redis节点并分别启动redis服务(容器跑起来并未自动启动redis服务):
docker run -it -d --name r2 -p 5002:6379 --net=net2 --ip=172.19.0.3 redis bash
docker run -it -d --name r3 -p 5003:6379 --net=net2 --ip=172.19.0.4 redis bash
docker run -it -d --name r4 -p 5004:6379 --net=net2 --ip=172.19.0.5 redis bash
docker run -it -d --name r5 -p 5005:6379 --net=net2 --ip=172.19.0.6 redis bash
docker run -it -d --name r6 -p 5006:6379 --net=net2 --ip=172.19.0.7 redis bash
docker exec -it r2 /usr/redis/src/redis-server /usr/redis/redis.conf
docker exec -it r3 /usr/redis/src/redis-server /usr/redis/redis.conf
docker exec -it r4 /usr/redis/src/redis-server /usr/redis/redis.conf
docker exec -it r5 /usr/redis/src/redis-server /usr/redis/redis.conf
docker exec -it r6 /usr/redis/src/redis-server /usr/redis/redis.conf安装redis-trib.rb
- redis-tribe是基于Ruby的Redis集群命令行工具
- 使用的是
yyyyttttwwww/redis,Ruby脚本和Ruby环境都已安装
# 在容器中(进入到6个redis容器中的任意一个,进行如下操作即可组网)
cd /usr/redis
mkdir cluster
cp /usr/redis/src/redis-trib.rb /usr/redis/cluster/
cd /usr/redis/cluster
apt-get install ruby
apt-get install rubygems
gem install redis创建Redis集群
- --replicas 1 表示每个主节点创建一个从节点
docker exec -it r1 bash
# 进到容器中
./redis-trib.rb create --replicas 1 172.19.0.2:6379 172.19.0.3:6379 172.19.0.4:6379 172.19.0.5:6379 172.19.0.6:6379 172.19.0.7:6379
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
172.19.0.2:6379
172.19.0.3:6379
172.19.0.4:6379
Adding replica 172.19.0.5:6379 to 172.19.0.2:6379
Adding replica 172.19.0.6:6379 to 172.19.0.3:6379
Adding replica 172.19.0.7:6379 to 172.19.0.4:6379
M: 74734d141f051f70a1b59c883dd1a7368e803ab9 172.19.0.2:6379
slots:0-5460 (5461 slots) master
M: 1b49e26dc5277e19bbc987329bad7f1fb4a36bb1 172.19.0.3:6379
slots:5461-10922 (5462 slots) master
M: 353faec9b383c10928ca476f361163b7165e9565 172.19.0.4:6379
slots:10923-16383 (5461 slots) master
S: 19c4869c9f70a8f64808e399ce6e3b84b834d03e 172.19.0.5:6379
replicates 74734d141f051f70a1b59c883dd1a7368e803ab9
S: aa6fdd39064848a56fff6d81268d0593fa11a588 172.19.0.6:6379
replicates 1b49e26dc5277e19bbc987329bad7f1fb4a36bb1
S: 7218cd5956cb6bd5d3f7f42228a4ec1a5d3ec4a4 172.19.0.7:6379
replicates 353faec9b383c10928ca476f361163b7165e9565
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 172.19.0.2:6379)
M: 74734d141f051f70a1b59c883dd1a7368e803ab9 172.19.0.2:6379
slots:0-5460 (5461 slots) master
M: 1b49e26dc5277e19bbc987329bad7f1fb4a36bb1 172.19.0.3:6379
slots:5461-10922 (5462 slots) master
M: 353faec9b383c10928ca476f361163b7165e9565 172.19.0.4:6379
slots:10923-16383 (5461 slots) master
M: 19c4869c9f70a8f64808e399ce6e3b84b834d03e 172.19.0.5:6379
slots: (0 slots) master
replicates 74734d141f051f70a1b59c883dd1a7368e803ab9
M: aa6fdd39064848a56fff6d81268d0593fa11a588 172.19.0.6:6379
slots: (0 slots) master
replicates 1b49e26dc5277e19bbc987329bad7f1fb4a36bb1
M: 7218cd5956cb6bd5d3f7f42228a4ec1a5d3ec4a4 172.19.0.7:6379
slots: (0 slots) master
replicates 353faec9b383c10928ca476f361163b7165e9565
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered创建成功。访问任意一个节点即可测试。
docker exec -it r1 bash
/usr/redis/src/redis-cli -c
127.0.0.1:6379>set a 10
-> Redirected to slot [15495] located at 172.19.0.4:6379 #
OK
172.19.0.4:6379> get a
"10"- /usr/redis/src/redis-cli -c 中的 -c 表示连接到redis cluster
- set a 10时,经过集群计算数据存储到172.19.0.4节点上
尝试把172.19.0.4(master)节点挂掉,并查看cluster节点状态:
docker container pause r3
docker exec -it r1 bash
root@a62d4263df70:/# /usr/redis/src/redis-cli -c
127.0.0.1:6379> cluster nodes
353faec9b383c10928ca476f361163b7165e9565 172.19.0.4:6379 master,fail - 1661308551183 1661308547172 3 connected
1b49e26dc5277e19bbc987329bad7f1fb4a36bb1 172.19.0.3:6379 master - 0 1661308571248 2 connected 5461-10922
7218cd5956cb6bd5d3f7f42228a4ec1a5d3ec4a4 172.19.0.7:6379 master - 0 1661308572250 7 connected 10923-16383
aa6fdd39064848a56fff6d81268d0593fa11a588 172.19.0.6:6379 slave 1b49e26dc5277e19bbc987329bad7f1fb4a36bb1 0 1661308574256 5 connected
74734d141f051f70a1b59c883dd1a7368e803ab9 172.19.0.2:6379 myself,master - 0 0 1 connected 0-5460
19c4869c9f70a8f64808e399ce6e3b84b834d03e 172.19.0.5:6379 slave 74734d141f051f70a1b59c883dd1a7368e803ab9 0 1661308573254 4 connected
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.19.0.7:6379
"10"并且此时get a,依然可以使用备用节点获取到数据。
恢复r3节点,再去get a,依然可以取到数据,只不过主备节点身份互换。
docker container unpause r3
# 再次进入到r1
docker exec -it r1 bash
/usr/redis/src/redis-cli -c
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.19.0.7:6379
"10"
172.19.0.7:6379> cluster nodes
aa6fdd39064848a56fff6d81268d0593fa11a588 172.19.0.6:6379 slave 1b49e26dc5277e19bbc987329bad7f1fb4a36bb1 0 1661308887352 5 connected
1b49e26dc5277e19bbc987329bad7f1fb4a36bb1 172.19.0.3:6379 master - 0 1661308884344 2 connected 5461-10922
353faec9b383c10928ca476f361163b7165e9565 172.19.0.4:6379 slave 7218cd5956cb6bd5d3f7f42228a4ec1a5d3ec4a4 0 1661308889360 7 connected
7218cd5956cb6bd5d3f7f42228a4ec1a5d3ec4a4 172.19.0.7:6379 myself,master - 0 0 7 connected 10923-16383
19c4869c9f70a8f64808e399ce6e3b84b834d03e 172.19.0.5:6379 slave 74734d141f051f70a1b59c883dd1a7368e803ab9 0 1661308888356 4 connected
74734d141f051f70a1b59c883dd1a7368e803ab9 172.19.0.2:6379 master - 0 1661308886350 1 connected 0-5460
172.19.0.7:6379>172.19.0.7变为master,172.19.0.4变为salve。
参考资料
- PXC8.0集群搭建遇见的坑
- Docker启动、进入容器,查看容器log
- Docker命令_各种参数简介(run、v、rm、-w、-u、-e)
- percona-xtrabackup官方文档 - Docker部署方法
- mysql 启动失败 详情,MySQL 启动失败的常见原因
提供云存储服务