单节点数据库瓶颈
我们知道,单节点数据库通常存在如下弊端:
- 大型互联网程序用户群体庞大,所以架构必须要特殊设计
- 单节点的数据库无法满足性能上的需求
- 单节点数据库没有冗余的设计,无法满足高可用特性
例如,在2016年春节,微信红包的业务量巨大:共有142亿个红包,比平时的业务量增加了75%,且每秒76万个红包。同时,产生了2900万张红包张片,5.16亿人参与,每秒的支付峰值达到20.8万。
如果这是一个单节点的MySQL数据库,则将带来性能上巨大的瓶颈。
那么,你一定会问,有没有MySQL集群方案,来处理这件事呢?
答案是肯定的!
MySQL集群方案
常见的MySQL集群方案有:
Replication
- 1、存储速度快;
- 2、弱一致性:在A节点写入的数据,无法保证把这条数据分发到集群的其他节点上,这就有可能出现在A节点写入的数据,在B节点上查不到这条数据。
由于弱一致性的特点,我们不能在Replication上保存高价值的数据,而是适合保存低价值的数据,如日志数据、新闻、论坛帖子数据等。
PXC(Percona XtraDB Cluster)
- 1、存储速度稍慢
- 2、强一致性:能保证数据同步的强一致性;在集群的A节点写入的数据,PXC方案一定会保证这条数据成功的同步到数据库集群的其他节点上。所以,PXC方案适合保存高价值的数据,如订单、账户、财务数据等等。
PXC原理
PXC 基于Mysql的Galera技术实现的数据库集群方案。在PXC集群中,任何一个数据库的节点都是可读可写的。可以在第一个节点中写入数据,在其他节点中就可以成功的读取这条数据,这体现了强一致性。
另外,在PXC集群中,集群上节点的数据库都是Mysql,我们可以使用Mysql官方的版本或Mysql的衍生版。
但是,建议的是,使用的数据库实例可以用PerconaServer,它是Mysql的改进版,性能提升很大。所以,建议使用PerconaServer去搭建Mysql集群。
PCX方案与Replication方案对比
PXC集群,数据同步是双向的。即,在任何一个Mysql节点上都是能够同时读写数据的。如下图:
而,Replication方案的数据读写是单向的。例如,在Master节点上写入数据,在Slave节点上能读到这条数据,但是在Slave上写入数据,Master节点上就会读不到这条数据。因为,Replication的方案是单向的。所以,Replication方案导致集群里面的节点不是同时可以进行读写。
PCX方案的数据强一致性
由上图可知,PXC采用同步复制机制,即事务在所有集群节点要么同时提交,要么不提交。
而Replication采用异步赋值机制,无法保证数据的一致性。
- 同步复制机制:同步机制要求必须在其他节点中也要成功的写入数据,才能算是一次写入的成功;
所以,把数据写入到第一个Mysql节点上后,还需要通过同步机制,把这个数据同步到其他节点,并且在其他节点成功的提交事务后,最后才算是写入成功。这个时候,第1个Mysql节点,才会把成功的节点告诉给Mysql 的客户端。如果有一个节点写入失败,那么这次写入就会算失败,不会同步到其他节点,客户端得到的反馈也是写入失败。
Replication数据弱一致性
Replication的异步复制机制,例如在第一个Mysql节点中写入数据,如果这个节点成功提交事务,就会直接返回写入成功的结果。但是,如果同步失败了,那么第二个节点可能就无法读到数据。这就好比你在淘宝上买东西,下了订单,付了款后,可是你却在订单列表中没有发现你的订单。这事就严重了。
所以,对于高价值数据,采用PXC集群式很有必要的!
PXC 集群实例与Replication集群实例对比
- Replication 集群实例:
- PXC集群实例:
把第二个节点的同步机制关闭,那么就会造成写入失败。这验证了PXC的强一致性原则。
PXC集群安装
首先,下载PXC集群,下载地址:
https://hub.docker.com/r/percona/percona-xtradb-cluster
安装PXC镜像
下载:docker pull percona/percona-xtradb-cluster
导入:docker load < /home/soft/pxc.tar.gz>
下载完成后:
由于percona-xtradb-cluster
名字较长,所以,可以进行修改:
docker tag docker.io/percona/percona-xtradb-cluster pxc
我们可以把原来的删除:
docker rmi docker.io/percona/percona-xtradb-cluster
现在假设我们要创建5个节点的PXC集群,那么我们就需要创建5个PXC容器:
创建出来的PXC容器,不要对接Docker以外的网络,否则不安全。
出于安全考虑,我们要先给PXC集群在Docker虚拟机内部单独划分一个网段,这个网段外部是无法直接访问的,可以通过Docker开放的端口供外部访问。
创建内部网络
出于安全考虑,需要给PXC集群实例创建Docker内部网络:
docker network create net1
//net1表示创建的网段名字
docker network inspect net1
//查看net1网段的信息
docker network rm net1
//删除net1网段
docker虚拟机自带的网段是172.17.0.xx,那么net1的ip 就是172.18.0.xx ,以此类推,当你创建第二个网段的时候,第二个网段的Ip就是172.19.0.xx 。。。
如果你想创建的网段不是172.18.0.xx,那么你可以自己规定:
docker network create --subnet=172.18.0.0/24 net1 //创建了一个地址为172.18.0.0 ,端口为24的,名称为net1的网段。
Docker容器的使用原则:
一旦创建容器,不要把业务数据保存在容器中,而要保存在宿主机中。
那,怎么做呢?——> 使用的技术就是“目录映射”
!
可以把宿主机上的一个目录映射到容器内。在运行容器的时候,把业务数据保存到这个映射目录里面,即存储到了宿主机的目录里面。
这样,一旦容器发生故障,只需要把这个容器停掉或删除掉,然后重新启动一个新的容器,然后把宿主机的目录映射给新的容器,那么新的容器启动后,就自带了这些业务数据。
但是,PXC这种方案,无法直接使用映射目录的方式,那么就需要采用另外一种目录映射的技术:“Docker卷
”。
创建Docker卷
docker volume create --name v1 //创建一个名称为v1的Docker卷
创建的这个Docker卷,在宿主机中能够看得见。因为这是在宿主机上的Docker创建的一个卷,而这个卷在宿主机上是能看到目录的。然后,把这个卷映射给容器,这样,当PXC容器启动后,就可以把数据映射到卷的目录中。我们通过宿主机可以看到通过映射出来的数据。
现在我们创建的这个卷在宿主机上的真实路径是:/var/lib/docker/volumes/v1/_data
有了这个路径,那么,当创建PXC容容器时,我们就可以把这个数据卷v1 映射到容器的Mysql目录中。
同时,你可以删除
这个数据卷: docker volume rm v1
创建PXC容器
- 只需要向PXC镜像传入运行参数就能创建出PXC容器
[root @ localhost / ] docker run -d -p 3306:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 --privileged --name=node1 --net=net1 --ip 172.18.0.2 pxc
解释:
docker run -d -p 3306:3306
//-d:创建出的PXC容器,需要在后台运行; -p 端口映射,把容器的3306端口映射到宿主机的3306端口上;- 路径映射:
-v v1:/var/lib/mysql
//v1数据卷映射到容器中的Mysql的数据目录 - 启动参数:
-e MySQL_ROOT_PASSWORD=abc123456
创建出的数据库实例,对应的密码(这里是abc123456) - 创建出来的PXC集群名字 :
-e CLUSTER_NAME=PXC
(这里是PXC) - 数据库节点之间同步时要用到的密码:
-e XTRABACKUP_PASSWORD=abc123456
(这里是abc123456) - 权限:
--privileged
(最高权限,可读可写可执行) - 给创建出来的容器起名字:
--name=node1
- 使用的内部网段:
--net=net1
- 使用的内部网段的IP地址:
--ip 172.18.0.2
- 镜像的指令:
pxc
执行指令后一个PXC的容器就会创建出来端口参数需要错开
CLUSTER_JOIN=node1
: 与node1节点进行同步分配ip地址,需要错开
实际操作:
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
注意:虽然上面语句一下子就执行了,但是实际上Mysql数据库的初始化不会这么快就完成,至少需要2分钟才能完成。所以,你需要等待。因为,如果第一个容器的Mysql没有初始化成功,就创建第二个PXC容器时,这第二个PXC容器启动时,会发生闪退。因为,第二个容器的MYSQL与第一个容器的MYsql做同步的时候,它会发现第一个容器的Mysql没有成功启动,那么第二个容器就会发生故障,导致第二个容器闪退。 所以,请你耐心等待第一个容器里的Mysql成功初始化,并且你通过客户端能连接到这个Mysql实例,你再去创建第二个、第三个.....PXC实例。
接着,我们创建数据库的连接:
这里我们使用在navicat Mysql上创建:
新建一个连接,取名为DB1,IP地址填宿主机的IP
,端口号也是填宿主机的端口号
,用户名是root,密码我这里填abc123456。
注意:在这之前,你的centOs7上先要安装mysql。具体安装过程请参考:
https://www.cnblogs.com/starof/p/4680083.html
https://blog.csdn.net/paullinjie/article/details/80340145
https://blog.csdn.net/wzhedward/article/details/71036689
安装完成后,请在centos7上开放防火墙的3306端口。命令: firewall-cmd --permanent --add-port=3306/tcp firewall-cmd --reload
同样,创建DB1节点成功后,我们可以陆续创建其他4个节点:DB2、DB3、DB4。
创建完成后,先启动docker: service docker restart
然后,创建五个volume:
docker volume create v1 docker volume create v2 docker volume create v3 docker volume create v4 docker volume create v5
创建PXC容器
我们就可以接在在centos7上创建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 docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v2:/var/lib/mysql --privileged --name=node2 --net=net1 --ip 172.18.0.3 pxc docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v2:/var/lib/mysql --privileged --name=node3 --net=net1 --ip 172.18.0.4 pxc docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v4:/var/lib/mysql --privileged --name=node4 --net=net1 --ip 172.18.0.5 pxc docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v5:/var/lib/mysql --privileged --name=node5 --net=net1 --ip 172.18.0.6 pxc
然后我们在,DB1上新建一个数据库test:
创建成功后,我们去创新DB2、DB3、DB4、DB5,可以看到这几个节点也同步了test数据库:
OK,接着我们在test数据库上创建一张数据表,命名为student:执行之后,表结构如下:
我们再刷新一下其他节点,可以看到其他节点的test数据库,也进行了同步:
同样,当你在其他节点上更新,也会进行同步。
这样,我们的PXC集群就成功的搭建了!