Docker 搞定 MySQL 高可用集群
1集群方案
-
Replication
-
速度快,但仅能保证弱一致性,适用于保存价值不高的数据,比如日志、帖子、新闻等。 -
采用 Master-Slave 结构,在 Master 写入会同步到 Slave,能从 Slave 读出;但在 Slave 写入无法同步到 Master。 -
采用异步复制,Master 写入成功就向客户端返回成功,但是同步 Slave 可能失败,会造成无法从 Slave 读出的结果 -
需要该方案的请查看我的另一篇文章:『Docker 实现 MySQL 主从复制』
-
PXC (Percona XtraDB Cluster)
-
速度慢,但能保证强一致性,适用于保存价值较高的数据,比如订单、客户、支付等。 -
数据同步是双向的,在任一节点写入数据,都会同步到其他所有节点,在任何节点上都能同时读写。 -
采用同步复制,向任一节点写入数据,只有所有节点都同步成功后,才会向客户端返回成功。事务在所有节点要么同时提交,要么不提交。
2安装 PXC 集群
-
安装镜像
$ docker pull percona/percona-xtradb-cluster:5.7.33
-
重命名镜像(缩短镜像名称)
$ docker tag percona/percona-xtradb-cluster:5.7.33 pxc
# 移除原镜像
$ docker rmi percona/percona-xtradb-cluster:5.7.33
-
创建 net1 网段
-
出于安全考虑,给PXC集群创建Docker内部网络
# 创建网段
$ docker network create --subnet=172.18.0.0/24 net1
# 查看网段
$ docker network inspect net1
# 删除网段
$ docker network rm net1
-
创建五个数据卷(pxc无法直接存取宿组机的数据,所以创建五个 docker 数据卷)
$ docker volume create v1
$ docker volume create v2
$ docker volume create v3
$ docker volume create v4
$ docker volume create v5
# 查看数据卷位置
$ docker inspect v1
# 删除数据卷
$ docker volume rm v1
-
创建 5 节点的 PXC 集群
-
第一个节点创建完成之后,需要等 1 分钟左右才能创建后面的节点。可以通过 Navicat连接第一个节点测试下,可以连接就说明可以了
# 创建第 1 个 MySQL 节点
$ docker run -d --name=mysql-node1 -p 3310:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v1:/var/lib/mysql --net=net1 --ip 172.18.0.2 pxc
# 创建第 2 个 MySQL 节点
$ docker run -d --name=mysql-node2 -p 3311:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=mysql-node1 -v v2:/var/lib/mysql --net=net1 --ip 172.18.0.3 pxc
# 创建第 3 个MySQL节点
$ docker run -d --name=mysql-node3 -p 3312:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=mysql-node1 -v v3:/var/lib/mysql --net=net1 --ip 172.18.0.4 pxc
#创建第 4 个 MySQL节点
$ docker run -d --name=mysql-node4 -p 3313:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=mysql-node1 -v v4:/var/lib/mysql --net=net1 --ip 172.18.0.5 pxc
# 创建第 5 个 MySQL 节点
$ docker run -d --name=mysql-node5 -p 3314:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=mysql-node1 -v v5:/var/lib/mysql --net=net1 --ip 172.18.0.6 pxc
-
测试集群
-
通过 Navicat 连接任意一个数据库,进行增、删、改操作操作,观察其它库是否进行同步操作
3Haproxy 负载均衡
-
虽然搭建了集群,但是不使用数据库负载均衡,单节点处理所有请求,负载高,性能差,如下图
-
使用Haproxy做负载均衡,可以将请求均匀地发送给每个节点,单节点负载低,性能好,如下图
-
安装haproxy镜像
$ docker pull haproxy:2.3.13
-
新建目录
$ mkdir -p /home/apps/haproxy
-
新建 Haproxy 配置文件
$ vim /home/apps/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:123456
#数据库负载均衡
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-node1 172.18.0.2:3306 check weight 1 maxconn 2000
server mysql-node2 172.18.0.3:3306 check weight 1 maxconn 2000
server mysql-node3 172.18.0.4:3306 check weight 1 maxconn 2000
server mysql-node4 172.18.0.5:3306 check weight 1 maxconn 2000
server mysql-node5 172.18.0.6:3306 check weight 1 maxconn 2000
#使用keepalive检测死链
option tcpka
-
在数据库集群中创建空密码、无权限用户 haproxy,来供 Haproxy 对 MySQL 数据库进行心跳检测
# 进入容器
$ docker exec -it mysql-node1 /bin/bash
# 登录mysql
$ mysql -uroot -p123456
# 创建用户
mysql> create user 'haproxy'@'%' identified by '';
-
创建第 1 个 Haproxy 负载均衡服务器
$ docker run -it -d --name haproxy-node1 -p 4001:8888 -p 4002:3306 --restart always --privileged=true -v /home/apps/haproxy:/usr/local/etc/haproxy --net=net1 --ip 172.18.0.7 haproxy:2.3.13
-
启动 Haproxy
# 进入容器
$ docker exec -it haproxy-node1 /bin/bash
# 启动haproxy
$ haproxy -f /usr/local/etc/haproxy/haproxy.cfg
4访问测试
-
页面访问
-
ip:4001/dbs,在配置文件中定义有用户名admin,密码:123456
-
数据库访问
-
使用 Navacat 访问代理集群,端口为 4002
-
测试 Docker 挂掉
-
分别下线第一和第二个节点,通过访问其它节点或代理节点都能正常使用
5节点宕机或重启
-
从节点宕机后的操作
-
如果指定的主节点没有宕机,直接启动从节点容器,数据会自动同步
-
主节点宕机后的操作
-
[重启用此操作] 如果主节点是最后一个离开集群的(说明数据是最新的),只要重启主节点即可,主节点的启动需要设置 safe_to_bootstrap: 1 才能启动
# 修改 grastate.dat
$ vim /var/lib/docker/volumes/v1/_data/grastate.dat
# 将以下值改为1
safe_to_bootstrap: 1
# 启动主节点
$ docker start mysql-node1
-
如果其他节点还在运行中,主节点挂掉了(说明主节点的数据已经不是最新的了),需要删除主节点容器,原来的数据卷无需删除(继续使用,避免数据丢失),然后再以从节点方式加入集群,注意加参数 "-e CLUSTER_JOIN=mysql-node2",指定可用的从节点启动
$ docker run -d --name=mysql-node1 -p 3310:3306 --privileged=true -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=mysql-node2 -v v1:/var/lib/mysql --net=net1 --ip 172.18.0.2 pxc
-
另一种启动方式,删除集群容器和数据卷中的grastate.dat文件,重新创建
-
该方案会以主节点的数据恢复,如果主节点数据不是最新的,会造成数据丢失
# 移除容器
docker rm mysql-node1 mysql-node2 mysql-node3 mysql-node4 mysql-node5
# 移除数据卷中的grastate.dat文件
rm -rf /var/lib/docker/volumes/v1/_data/grastate.dat
rm -rf /var/lib/docker/volumes/v2/_data/grastate.dat
rm -rf /var/lib/docker/volumes/v3/_data/grastate.dat
rm -rf /var/lib/docker/volumes/v4/_data/grastate.dat
rm -rf /var/lib/docker/volumes/v5/_data/grastate.dat
# 按上面的方式重新创建集群容器
6参考
-
https://www.cnblogs.com/wanglei957/p/11819547.html -
节点宕机:https://www.cnblogs.com/wangbiaohistory/p/14638935.html