Docker 通过PXC+Nginx实现高可用强一致性的mysql集群(单机多节点)

481 阅读8分钟

Docker 通过PXC+Nginx实现高可用强一致性的mysql集群(单机多节点)

1.基础软件

本人的构建环境如下:

  • Ctenos7
  • Docker version 20.10.21, build baeda1f

2.基础原理

  • 数据同步时双向的,任何一个mysql节点写入数据,都会同步到集群中其它的节点。
  • 同步复制,事务在所有集群节点要么同时提交,要么同时不提交

Untitled.png

上图为PXC方案,支持各个节点都可以独写

Untitled 1.png

上图为同步方案,任何数据都是同步复制,同时提交,要么同时不提交

3.安装PXC镜像

#拉取pxc镜像
docker pull percona/percona-xtradb-cluster:5.7.30
#此次指定版本,8.0后需要配置证书

#修改镜像名称
docker tag percona/percona-xtradb-cluster:5.7.30 pxc

#删除镜像
docker rmi percona/percona-xtradb-cluster:5.7.30

#查看镜像
docker images

Untitled 2.png

4.创建内部网络

出于安全考虑,需要给 PXC 集群实例创建 Docker内部网络

#创建内部网段,24位,名称pxc-network:
docker network create --subnet=172.30.0.0/24 pxc-network
#注意:不能和宿主机网络一致

#查看pxc-network网段
docker inspect pxc-network

#删除pxc-network(这里不执行,参考)
docker network rm pxc-network

Untitled 3.png

5.创建docker数据卷

注意:pxc不支持映射目录,所以采样映射数据卷的方式

Docker 卷是容器中的 PXC 节点映射数据目录的解決办法

一旦创建出docker容器,尽量不要把业务数据存在容器内,因为出问题的话数据可能就找不到了。 可以把业务数据保存在宿主机内,通过映射技术将宿主机上的目录映射到容器内。在运行容器的时候,把业务数据保存在映射目录里,也就是存储到宿主机上面。如果容器出什么问题,可以在创建一个容器,再将目录映射给该容器,则业务数据就导入了

#创建数据卷 v1 v2 v3 v4 v5
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

Untitled 4.png

6.创建pxc容器

开始创建5个MySQL节点

命令参数说明:端口3306,密码123456,集群名称PXC,同步数据密码123456,映射数据目录到宿主机的v1数据卷,给予最高权限,名称叫node1,网段为pxc-network,ip指定为172.30.0.2,运行的镜像是pxc。

6.1第一个节点

docker run -d -p 3301:3306 -e MYSQL_ROOT_PASSWORD=test.888 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=test.888 -v v1:/var/lib/mysql --privileged --name=pxc-node1 --net=pxc-network --ip 172.30.0.2 pxc

注意:第一个节点启动比较慢,需要等待1分钟时间,可以使用数据据连接工具连接

Untitled 5.png

6.2第2,3,4,5个节点

docker run -d -p 3302:3306 -e MYSQL_ROOT_PASSWORD=test.888 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=test.888 -e CLUSTER_JOIN=pxc-node1 -v v2:/var/lib/mysql --privileged --name=pxc-node2 --net=pxc-network --ip 172.30.0.3 pxc

docker run -d -p 3303:3306 -e MYSQL_ROOT_PASSWORD=test.888 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=test.888 -e CLUSTER_JOIN=pxc-node1 -v v3:/var/lib/mysql --privileged --name=pxc-node3 --net=pxc-network --ip 172.30.0.4 pxc

docker run -d -p 3304:3306 -e MYSQL_ROOT_PASSWORD=test.888 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=test.888 -e CLUSTER_JOIN=pxc-node1 -v v4:/var/lib/mysql --privileged --name=pxc-node4 --net=pxc-network --ip 172.30.0.5 pxc

docker run -d -p 3305:3306 -e MYSQL_ROOT_PASSWORD=test.888 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=test.888 -e CLUSTER_JOIN=pxc-node1 -v v5:/var/lib/mysql --privileged --name=pxc-node5 --net=pxc-network --ip 172.30.0.6 pxc

7.验证PXC集群

可以使用navicat连接3301/3302/3303/3304/3305的数据库

Untitled 6.png

可以再3301先建数据库testdb1,并新建user表,发现3302/3303/3304/3305 数据库都同步成功了

Untitled 7.png

同步成功!

8.数据库负载均衡

虽然搭建了集群,但是不使用数据库负载均衡,单节点处理所有请求,负载高,性能差

Untitled 8.png

将请求均匀地发送给集群中的每一个节点。

  • 所有请求发送给单一节点,其负载过高,性能很低,而其他节点却很空闲。
  • 使用nginx或者Haproxy做负载均衡,可以将请求均匀地发送给每个节点,单节点负载低,性能好

Untitled 9.png

负载均衡首先是数据库的集群,加入5个集群,每次请求都是第一个的话,有可能第一个数据库就挂掉了,所以更优的方案是对不同的节点都进行请求,这就需要有中间件进行转发,比较好的中间件有nginx,haproxy等。

nginx作为负载均衡的中间件


#tcp/ip
stream{
    #mysql 负载均衡
    upstream mysql{
        server 100.100.200.213:3301 weight=1;
        server 100.100.200.213:3302 weight=1;
        server 100.100.200.213:3303 weight=1;
    }
    server {
        listen 3306;
        proxy_pass mysql;
    }
}

9.程序连接

#此处的端口就是nginx对外映射的端口 3306
他会随机分配到几个节点去查询数据

username: root
password: test.888
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://100.100.200.213:3306/ecdb?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false

10.热备份数据

冷备份

  • 冷备份是关闭数据库时候的备份方式,通常做法是拷贝数据文件
  • 是简单安全的一种备份方式,不能在数据库运行时备份。
  • 大型网站无法做到关闭业务备份数据,所以冷备份不是最佳选择

热备份

  • 热备份是在系统运行状态下备份数据

MySQL常见的热备份有LVM和XtraBackup两种方案

  • LVM:linux的分区备份命令,可以备份任何数据库;但是会对数据库加锁,只能读取;而且命令复杂
  • XtraBackup:不需要锁表,而且免费

XtraBackup

XtraBackup是一款基于InnoDB的在线热备工具,具有开源免费,支持在线热备,占用磁盘空间小,能够非常快速地备份与恢复mysql数据库

  • 备份过程中不锁表,快速可靠
  • 备份过程中不会打断正在执行地事务
  • 备份数据经过压缩,占用磁盘空间小

全量备份和增量备份

  • 全量备份:备份全部数据。备份过程时间长,占用空间大。第一次备份要使用全量备份
  • 增量备份: 只备份变化的那部分数据。备份的时间短,占用空间小。第二次以后使用增量备份
#PXC全量备份
#备份要在某个PXC节点的容器内进行,但应该把备份数据保存到宿主机内。所以采用目录映射技术。
先新建Docker卷:
docker volume create backup

#挑选一个PXC节点pxc-node1,将其容器停止并删除,然后重新创建一个增加了backup目录映射的node1容器
#注意:由于PXC各个节点数据节点都是一致的,所以只需要进入一个节点进行备份就行了。

docker stop pxc-node1
docker rm pxc-node1# 数据库数据保存在Docker卷v1中,不会丢失
# 参数改变:
# 1. -e CLUSTER_JOIN=pxc-node2;原来其他节点是通过node1加入集群的,现在node1重新创建,需要选择一个其他节点加入集群
# 2. -v backup:/data;将Docker卷backup映射到容器的/data目录
docker run -d -p 3301:3306 -e MYSQL_ROOT_PASSWORD=test.888 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=test.888 -v v1:/var/lib/mysql -v backup:/data -e CLUSTER_JOIN=pxc-node2 --net=pxc-network --privileged --ip 172.30.0.2 --name=pxc-node1 pxc

#进入pxc-node1节点
#进入节点
docker exec -it pxc-node1 /bin/bash
 
#更新update
yum update
#注意:会提示没有权限(这代表进入这个node1服务中的时候没有权限操作,所以我们要给到root用户进入服务)

#退出当前服务
ctrl+d
 
#重新以root角色进入docker服务,随便进入一个节点,这里我进入node1
docker exec -it -u 0 pxc-node1 /bin/bash
 
#执行update更新
yum update
 
#安装xtrabackup
yum install percona-xtrabackup-24
 
#安装完后进行全量备份:
innobackupex --user=root --password=MySQL密码 /data/backup/full
 
#执行完后自动开始全量备份

#切换到全量备份文件夹
cd /data/backup/full
 
#查看
ls

#=====================================================
#退出docker服务,由于有目录映射,所以宿主机上也会看到文件,具体方法:
#查看宿主机备份的数据目录在哪:
docker inspect backup
 
#切换到该文件夹
cd /var/lib/docker/volumes/backup/_data
 
#查看
ls
 
发现有backup目录,进入backup目录里面的full目录中查看,发现有全量备份文件

11.冷还原

MySQL的数据还原方式不像备份一样,MySQL数据还原只有冷还原,docker服务和单机节点差异是,docker还原的时候需要把docker的PXC集群解散掉,删除各个节点,之后新建一个新的节点并 进行冷还原,最后新建其他节点和当前节点进行数据同步;

docker stop #掉各个节点
 
docker rm #删掉各个节点
 
docker volume rm  #删掉各个数据卷,这里删掉的是pxc服务的数据卷不是backup备份文件数据卷,千万别用删除孤卷命令,因为解散pxc后backup卷也是孤卷了,删除孤卷命令会把备份数据也删掉了
 
新建一个新节点,命令和搭建pxc集群一致
 
#进入该节点
docker exec -it -u 0 node1 bash
 
#安装xtrabackup
 
#执行MySQL数据清空指令
rm -rf /var/lib/mysql/*
 
#执行还原命令
innodackupex --user=root --password=密码 --apply-back /data/backup/full/备份文件名/
 
这里的--apply-back参数指的是回滚掉全量备份之间产生的事务差异数据

12.定时备份

crontab 计划任务

#
crontab -e

#添加计划任务
00 02 * * * /var/lib/mysql/backup.sh

#crontab 计划任务在添加或修改后,需要保存并重启服务才能生效
systemctl restart crond