传统的单节点数据库无法应对高负载,满足大型互联网的需求。同时,单节点数据库没有冗余设计,无法保证高可用。因此,需要数据库集群技术。
MySQL作为一种免费的数据库,受到了业界的喜爱。常见的MySQL集群方案有Replication
和PXC (Percona XtraDB Cluster)
两种。
指标 | Replication | PXC |
---|---|---|
速度 | 快 | 慢 |
数据一致性 | 弱一致性,异步复制,无法保证数据的一致性 | 强一致性,同步复制,事务在所有的集群节点要么同时提交,要么不提交 |
适用场景 | 低价值数据,如日志、新闻和帖子等 | 高价值数据,如:订单、账户和财务信息等 |
这里,我们主要介绍一下PXC集群方案,建议PXC使用PerconaServer(MySQL改进版,性能提升较大)。这里我们利用Docker进行PXC集群安装。
首先,从Docker hub上搜索Percona,可以看到percona/percona-xtradb-cluster,使用docker pull percona/percona-xtradb-cluster
下载该镜像。
因为镜像的名称很长,利用docker tag
和docker rmi
指令可以将镜像重命名为pxc。
接着,处于安全考虑,需要给PXC集群实例创建Docker内部网络,创建docker内部网络的指令有
其中,docker默认网段为172.17.XXX.XXX,此时创建的net1的网段为172.18.XXX.XXX,当然也可以通过下述方式指定。
# 创建网段
docker network create --subnet=172.19.0.0/24 net1
# 查看网段信息
docker network inspect net1
/24 表示这个网络的子网掩码为:255.255.255.0
即这个地址的前24位为网络位,这个网段内最多有2的8次方个主机
为了将容器中的PXC节点的数据保存在宿主机,并数据添加映射目录,这里采用创建Docker卷的解决办法。首先,在宿主机上创建docker卷,接着,再将这个卷映射给容器,保存数据,这样在容器故障之后,可以直接运行一个新的容器,保证集群的高可用和数据的一致性。
# 创建docker卷
docker volume create --name v1
# 查看docker卷的信息
docker inspect v1
# 删除docker卷
# docker volume rm v1
可以看到数据卷创建到了宿主机的/var/lib/docker/volumes/v1/_data
目录下。
创建PXC容器
# -d: 后台运行 -p: 端口映射 -v: 数据卷v1映射到/var/lib/mysql
docker run -d -p 3306:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=cluster1 -e XTRABACKUP_PASSWORD=123456 --privileged --name=node1 --net=net1 --ip 172.19.0.2 pxc
# 查看pxc容器是否创建成功
docker ps
以五个MySQL集群为例,创建一个PXC集群,运行脚本pxc.sh
如下:
echo "create net..."
docker network create --subnet=172.19.0.0/24 net1
echo "create docker volume..."
docker volume create v1
docker volume create v2
docker volume create v3
docker volume create v4
docker volume create v5
echo "create node1...."
docker run -d -p 30001:3306 --net=net1 --name=node1 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-v v1:/var/lib/mysql \
--privileged \
--ip 172.19.0.2 \
pxc
sleep 2m
echo "create node2..."
docker run -d -p 30002:3306 --net=net1 --name=node2 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v2:/var/lib/mysql \
--privileged \
--ip 172.19.0.3 \
pxc
sleep 30s
echo "create node3..."
docker run -d -p 30003:3306 --net=net1 --name=node3 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v3:/var/lib/mysql \
--privileged \
--ip 172.19.0.4 \
pxc
sleep 30s
echo "create node4..."
docker run -d -p 30004:3306 --net=net1 --name=node4 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v4:/var/lib/mysql \
--privileged \
--ip 172.19.0.5 \
pxc
sleep 30s
echo "create node5..."
docker run -d -p 30005:3306 --net=net1 --name=node5 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v5:/var/lib/mysql \
--privileged \
--ip 172.19.0.6 \
pxc
但是,这里遇到了无法启动从节点的问题,更换了pxc镜像版本为5.7版本解决。Stack Overflow上关于该问题的问答。
echo "clearing..."
docker kill node1
docker kill node2
docker kill node3
docker kill node4
docker kill node5
docker rm node1
docker rm node2
docker rm node3
docker rm node4
docker rm node5
docker volume rm v1
docker volume rm v2
docker volume rm v3
docker volume rm v4
docker volume rm v5
echo "create docker volume"
docker volume create v1
docker volume create v2
docker volume create v3
docker volume create v4
docker volume create v5
echo "create node1..."
docker run -d -p 30001:3306 --net=net1 --name=node1 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-v v1:/var/lib/mysql \
--privileged \
--ip 172.19.0.2 \
percona/percona-xtradb-cluster:5.7
sleep 2m
echo "create node2..."
docker run -d -p 30002:3306 --net=net1 --name=node2 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v2:/var/lib/mysql \
--privileged \
--ip 172.19.0.3 \
percona/percona-xtradb-cluster:5.7
sleep 30s
echo "create node3..."
docker run -d -p 30003:3306 --net=net1 --name=node3 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v3:/var/lib/mysql \
--privileged \
--ip 172.19.0.4 \
percona/percona-xtradb-cluster:5.7
sleep 30s
echo "create node4..."
docker run -d -p 30004:3306 --net=net1 --name=node4 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v4:/var/lib/mysql \
--privileged \
--ip 172.19.0.5 \
percona/percona-xtradb-cluster:5.7
sleep 30s
echo "create node5..."
docker run -d -p 30005:3306 --net=net1 --name=node5 \
-e CLUSTER_NAME=PXC \
-e MYSQL_ROOT_PASSWORD=123456 \
-e XTRABACKUP_PASSWORD=123456 \
-e CLUSTER_JOIN=node1 \
-v v5:/var/lib/mysql \
--privileged \
--ip 172.19.0.6 \
percona/percona-xtradb-cluster:5.7
在重新创建容器时,一定要先将docker卷删除,否则,Mysql会报如下错误:
InnoDB: Table flags are 0 in the data dictionary but the flags in file ./ibdata1 are 0x4800!
另外,因为Windows系统的文件换行使用的是\r\n,而Unix系统是\n,执行sh脚本时,Windows下编辑的脚本上传到Linux系统后可能会出现:bash: $’\r’: command not found。这里,采用如下方式解决问题。
yum install -y dos2unix
dos2unix pxc.sh
值得注意的是,一定要先确保主节点创建成功,然后再创建从节点,这也是为什么sh脚本延时的原因。测试方法就是通过数据库客户端工具连接测试一下。
注意,创建容器可能会失败,此时,我们可以利用docker logs node1
指令查看启动信息。如果想要docker容器在宿主机重启后自动运行,则在docker run
指令中添加--restart=always
配置即可。
为了测试PXC集群数据是否同步,这里在node1节点创建一个数据表sys_user:
create table sys_user
(
u_id int auto_increment primary key,
u_name varchar(50) not null
)