mysql架构的一种演进过程

1.架构存在的问题

 

在日常系统的DBServer方面中,有些只使用了单节点服务,如果面对大并发,海量数据的存储,显然单节点的系统架构将存在很严重的问题,所以接下来,针对应对大并发、海量数据存储等问题,我们将实施Mysql的集群演化过程。

2.Mysql集群方案演化

2.1读写分离架构

2.1.1说明

我们一般应用对数据库而言都是“读多写少”,也就是说对数据库读取数据的压力比较大,有一个数据库集群的方案就是:其中一个是主库,负责写入数据,我们称之为“写库”,其它都是从库,负责读取数据,我们称之为“读库”。

因此会衍生出一种下面的架构

 

从上面的架构中,可以看出:

1)数据库从之前的单节点变成多节点提供服务
2)主节点数据,同步到从节点数据
3)应用程序需要连接到2个数据库节点,并且在程序内部实现判断读写操作。

2.1.2新问题

这种架构存在2个问题

1)应用程序需要连接到多个节点,对应用程序开发而言变得复杂

#解决方案:
1)通过中间件
2)使用SpringAOP功能实现

2)主从之间的同步,是异步完成的,也就意味着这是一种弱一致性

#解决方案
1)通过PXC集群解决

2.2中间件

2.2.1说明

通过上面的架构,可以看出,应用程序会连接到多个节点,使得应用程序的复杂度会提升,可以通过中间件解决,如下:

 

从架构中,可以看出:

1)应用程序只需要连接到中间件即可,无需连接多个数据库节点
2)应用程序无需区分读写操作,对中间件直接进行读写操作即可
3)在中间件进行读写的分离,读发送到从节点,写发送到主节点

2.2.2新问题

该架构中也存在问题,中间件的性能成为了系统的瓶颈,那么继续演化吧

 

这样的话,中间的性能得到了保证,但是也带来了新的问题,应用系统依然需要连接到两个中间件,又为系统带来了复杂度。

2.3.负载均衡

2.3.1说明

为了解决以上问题,我们将继续优化架构,在应用程序和中间件之间增加proxy代理,有代理来完成负载均衡的功能,应用程序只需要对接到peoxy‘即可。

 

2.4PXC集群架构

2.4.1说明

在前面的架构中,都是基于MYSQL主从的架构,那么在主从架构中,弱一致性问题依然没有解决,如果在需要强一致性的需求中,显然这架构是不能应对的,比如:交易数据。

PXC提供了读写强一致的功能,可以保证数据在任何一个节点写入的同时,可以同步到其它节点,也就意味着可以从其它的任何节点进行读操作,无延迟。

架构如下:

 

2.5混合架构

在前面的PXC架构中,虽然可以实现事务的强一致性,但是它是通过牺牲了性能换来的一致性,如果在某些业务场景下,没有强一致性的需求,那么PXC就不适合了。所以,在我们的系统架构中,需要将这两种方案综合起来,这样才是一个较为完善的架构。

 

3.安装docker

为了能够快速模拟上面的架构演进过程,我们选取了centos7系统的docker镜像方式,来快速搭建每个组件,以在短时间内完成实验。在生产过程中,只需将每个组件的搭建过程,进行相应的替换即可。

3.1安装docker

cat /etc/redhat-release
uname -r
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum makecache  #生成仓库缓存
yum install docker -y

3.2启动docker

systemctl start docker  #启动docker
systemctl enable docker #开机启动docker
systemctl status docker #查看docker状态

3.3docker版本

[root@bigdata1 ~]# docker version
Client:
 Version:         1.13.1
 API version:     1.26
 Package version: docker-1.13.1-162.git64e9980.el7.centos.x86_64
 Go version:      go1.10.3
 Git commit:      64e9980/1.13.1
 Built:           Wed Jul  1 14:56:42 2020
 OS/Arch:         linux/amd64

Server:
 Version:         1.13.1
 API version:     1.26 (minimum version 1.12)
 Package version: docker-1.13.1-162.git64e9980.el7.centos.x86_64
 Go version:      go1.10.3
 Git commit:      64e9980/1.13.1
 Built:           Wed Jul  1 14:56:42 2020
 OS/Arch:         linux/amd64
 Experimental:    false

3.4镜像加速

vi /etc/docker/daemon.json
{
 "registry-mirrors": ["http://hub-mirror.c.163.com"]
}
#重启docker
systemctl restart docker

3.5小妙招

#快速清理多个docker容器
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

4.搭建主从复制集群

4.1搭建主从集群01

4.1.1搭建01主库

#创建目录
mkdir -p /data/mysql/master01
cd /data/mysql/master01
mkdir conf data
chmod -R 7777 *

#创建配置文件
vi /data/mysql/master01/conf/my.cnf

#输入以下内容
[mysqld]
log-bin=mysql-bin
server-id=1
lower_case_table_names=1

#创建容器
docker create --name percona-master01 -v /data/mysql/master01/data:/var/lib/mysql -v /data/mysql/master01/conf:/etc/my.cnf.d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root percona

#启动
docker start percona-master01 && docker logs -f percona-master01

#创建同步账户以及授权
create user 'backup'@'%' identified by '123';
grant replication slave on *.* to 'backup'@'%';
flush privileges;

#查看master状态
SHOW MASTER STATUS;
#查看二进制日志相关的配置项
SHOW GLOBAL VARIABLES LIKE 'binlog%';
#查看server相关的配置项
SHOW GLOBAL VARIABLES LIKE 'server%';

4.1.2搭建01从库

#创建目录
mkdir -p /data/mysql/slave01
cd /data/mysql/slave01
mkdir conf data
chmod -R 7777 *

#创建配置文件
vi /data/mysql/slave01/conf/my.cnf

#输入以下内容
[mysqld]
log-bin=mysql-bin
server-id=2
lower_case_table_names=1

#创建容器
docker create --name percona-slave01 -v /data/mysql/slave01/data:/var/lib/mysql -v /data/mysql/slave01/conf:/etc/my.cnf.d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=root percona

#启动
docker start percona-slave01 && docker logs -f percona-slave01

#设置master相关信息
CHANGE MASTER TO
MASTER_HOST='192.168.56.11',
MASTER_USER='backup',
MASTER_PASSWORD='123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=743;

#启动同步
START SLAVE;

#查看master状态
show slave status;

4.2搭建主从集群02

4.2.1搭建02主库

#创建目录
mkdir -p /data/mysql/master02
cd /data/mysql/master02
mkdir conf data
chmod -R 7777 *

#创建配置文件
vi /data/mysql/master02/conf/my.cnf

#输入以下内容
[mysqld]
log-bin=mysql-bin
server-id=1
lower_case_table_names=1

#创建容器
docker create --name percona-master02 -v /data/mysql/master02/data:/var/lib/mysql -v /data/mysql/master02/conf:/etc/my.cnf.d -p 3316:3306 -e MYSQL_ROOT_PASSWORD=root percona

#启动
docker start percona-master02 && docker logs -f percona-master02

#创建同步账户以及授权
create user 'backup'@'%' identified by '123';
grant replication slave on *.* to 'backup'@'%';
flush privileges;

#查看master状态
SHOW MASTER STATUS;
#查看二进制日志相关的配置项
SHOW GLOBAL VARIABLES LIKE 'binlog%';
#查看server相关的配置项
SHOW GLOBAL VARIABLES LIKE 'server%';

4.2.2搭建02从库

#创建目录
mkdir -p /data/mysql/slave02
cd /data/mysql/slave02
mkdir conf data
chmod -R 7777 *

#创建配置文件
vi /data/mysql/slave02/conf/my.cnf

#输入以下内容
[mysqld]
log-bin=mysql-bin
server-id=2
lower_case_table_names=1

#创建容器
docker create --name percona-slave02 -v /data/mysql/slave02/data:/var/lib/mysql -v /data/mysql/slave02/conf:/etc/my.cnf.d -p 3317:3306 -e MYSQL_ROOT_PASSWORD=root percona

#启动
docker start percona-slave02 && docker logs -f percona-slave02

#设置master相关信息
CHANGE MASTER TO
MASTER_HOST='192.168.56.11',
MASTER_USER='backup',
MASTER_PASSWORD='123',
MASTER_PORT=3316,
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=743;

#启动同步
START SLAVE;

#查看master状态
show slave status;

5.mycat中间件

基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能以及众多成熟的使用案例使得MYCAT一开始就拥有一个很好的起点,站在巨人的肩膀上,我们能看到更远。业界优秀的开源项目和创新思路被广泛融入到MYCAT的基因中,使得MYCAT在很多方面都领先于目前其他一些同类的开源项目,甚至超越某些商业产品。

MYCAT背后有一支强大的技术团队,其参与者都是5年以上软件工程师、架构师、DBA等,优秀的技术团队保证了MYCAT的产品质量。

MYCAT并不依托于任何一个商业公司,因此不像某些开源项目,将一些重要的特性封闭在其商业产品中,使得开源项目成了一个摆设。

1)一个用于MySQL读写分离和与数据切分的高可用中间件
2)一个模拟为MySQLServer的超级数据库代理
3)一个能平滑扩展支持1000亿大表的分布式数据库系统 (普通单表1kw以下)
4)一个可管控多种关系数据库的数据库路由器

5.1mycat读写分离

cd /data
tar -xvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
cp -r /data/mycat /data/mycat01
cd /data/mycat01

#修改配置文件
vi /data/mycat01/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
        <system>
                <property name="nonePasswordLogin">0</property>
                <property name="useHandshakeV10">1</property>
                <property name="useSqlStat">0</property>
                <property name="useGlobleTableCheck">0</property>
                <property name="sequnceHandlerType">2</property>
                <property name="subqueryRelationshipCheck">false</property>
                <property name="processorBufferPoolType">0</property>
                <property name="handleDistributedTransactions">0</property>
                <property name="useOffHeapForMerge">1</property>
                <property name="memoryPageSize">64k</property>
                <property name="spillsFileBufferSize">1k</property>
                <property name="useStreamOutput">0</property>
                <property name="systemReserveMemorySize">384m</property>
                <property name="useZKSwitch">false</property>
        </system>
        <user name="itcast" defaultAccount="true">
                <property name="password">123</property>
                <property name="schemas">itcast</property>
        </user>
</mycat:server>


vi /data/mycat01/conf/schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 配置数据表 -->
        <schema name="itcast" checkSQLschema="true" sqlMaxLimit="100">
                <table name="tb_user" dataNode="dn1" rule="mod-long" />
        </schema>
    <!-- 配置分片关系 -->
        <dataNode name="dn1" dataHost="cluster1" database="itcast" />
    <!-- 配置连接信息 -->
        <dataHost name="cluster1" maxCon="1000" minCon="10" balance="3"
                          writeType="1" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="w1" url="192.168.56.11:3306" user="root" password="root">
                        <readHost host="w1r1" url="192.168.56.11:3307" user="root" password="root" />
                </writeHost>
        </dataHost>
</mycat:schema>


vi /data/mycat01/conf/rule.xml

        <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- how many data nodes -->
                <property name="count">1</property>
        </function>
       
       
#设置JMX端口    
vi wrapper.conf   
wrapper.java.additional.9=-Dcom.sun.management.jmxremote.port=11985
#设置服务端口
vi server.xml
<property name="serverPort">18067</property>
<property name="managerPort">19067</property>
#启动验证
./mycat console

vi startup_nowrap.sh
:set ff=unix
:wq
#启动
./startup_nowrap.sh

测试

create table `TB_USER`(
`id` bigint(20) not null auto_increment,
`type` int(10) default null,
`title` varchar(100) default null,
primary key(`id`)
) ENGINE=INNODB auto_increment=1 default charset=utf8;

insert into `TB_USER`(`id`,`type`,`title`) values('1','1','www.baidu.com');
insert into `TB_USER`(`id`,`type`,`title`) values('2','7','www.baidu.com');
insert into `TB_USER`(`id`,`type`,`title`) values('3','5','www.baidu.com');
insert into `TB_USER`(`id`,`type`,`title`) values('4','2','www.baidu.com');

5.2mycat双主双从读写分离

#修改配置文件
vi /data/mycat01/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
        <system>
                <property name="nonePasswordLogin">0</property>
                <property name="useHandshakeV10">1</property>
                <property name="useSqlStat">0</property>
                <property name="serverPort">8066</property>
                <property name="managerPort">9066</property>
                <property name="useGlobleTableCheck">0</property>
                <property name="sequnceHandlerType">2</property>
                <property name="subqueryRelationshipCheck">false</property>
                <property name="processorBufferPoolType">0</property>
                <property name="handleDistributedTransactions">0</property>
                <property name="useOffHeapForMerge">1</property>
                <property name="memoryPageSize">64k</property>
                <property name="spillsFileBufferSize">1k</property>
                <property name="useStreamOutput">0</property>
                <property name="systemReserveMemorySize">384m</property>
                <property name="useZKSwitch">false</property>
        </system>
        <user name="itcast" defaultAccount="true">
                <property name="password">123</property>
                <property name="schemas">itcast</property>
        </user>
</mycat:server>


vi /data/mycat01/conf/schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 配置数据表 -->
        <schema name="itcast" checkSQLschema="true" sqlMaxLimit="100">
                <table name="tb_user" dataNode="dn1,dn2" rule="mod-long" />
        </schema>
    <!-- 配置分片关系 -->
        <dataNode name="dn1" dataHost="cluster1" database="itcast" />
        <dataNode name="dn2" dataHost="cluster2" database="itcast" />
    <!-- 配置连接信息 -->
        <dataHost name="cluster1" maxCon="1000" minCon="10" balance="3"
                          writeType="1" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="w1" url="192.168.56.11:3306" user="root" password="root">
                        <readHost host="w1r1" url="192.168.56.11:3307" user="root" password="root" />
                </writeHost>
        </dataHost>
        <dataHost name="cluster2" maxCon="1000" minCon="10" balance="3"
                          writeType="1" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="w2" url="192.168.56.11:3316" user="root" password="root">
                        <readHost host="w2r2" url="192.168.56.11:3317" user="root" password="root" />
                </writeHost>
        </dataHost>
</mycat:schema>

vi /data/mycat01/conf/rule.xml

        <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- how many data nodes -->
                <property name="count">2</property>
        </function>

测试

insert into `tb_user`(`id`,`type`,`title`) values('1','1','www.baidu.com');
insert into `tb_user`(`id`,`type`,`title`) values('2','7','www.baidu.com');
insert into `tb_user`(`id`,`type`,`title`) values('3','5','www.baidu.com');
insert into `tb_user`(`id`,`type`,`title`) values('4','2','www.baidu.com');

update `tb_user` set `type`='10' where `id`=2;

select * from `tb_user` order by id;

5.3mycat集群

cd /data
cp -R mycat01 mycat02

#设置jmx端口
vi /data/mycat02/conf/wrapper.conf
wrapper.java.additional.6=-Dcom.sun.management.jmxremote.port=1984

#修改服务端口及管理端口
vi /data/mycat01/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
        <system>
                <property name="nonePasswordLogin">0</property>
                <property name="useHandshakeV10">1</property>
                <property name="useSqlStat">0</property>
                <property name="serverPort">8067</property>
                <property name="managerPort">9067</property>
                <property name="useGlobleTableCheck">0</property>
                <property name="sequnceHandlerType">2</property>
                <property name="subqueryRelationshipCheck">false</property>
                <property name="processorBufferPoolType">0</property>
                <property name="handleDistributedTransactions">0</property>
                <property name="useOffHeapForMerge">1</property>
                <property name="memoryPageSize">64k</property>
                <property name="spillsFileBufferSize">1k</property>
                <property name="useStreamOutput">0</property>
                <property name="systemReserveMemorySize">384m</property>
                <property name="useZKSwitch">false</property>
        </system>
        <user name="itcast" defaultAccount="true">
                <property name="password">123</property>
                <property name="schemas">itcast</property>
        </user>
</mycat:server>

6.负载均衡

6.1Haproxy

#拉取镜像
docker pull docker.io/haproxy

#创建目录,用于存放配置文件
mkdir -p /data/haproxy
vi /data/haproxy/haproxy.cfg

global
        maxconn         10000
        log             127.0.0.1 local0
        daemon
defaults
        mode            http
        log             global
        option          httplog
        option          dontlognull
        option http-server-close
        option forwardfor except 127.0.0.0/8
        option          redispatch
        retries         3
        timeout http-request 10s
        timeout queue   30s
        timeout connect 5s
        timeout client  30s
        timeout server  30s
        timeout http-keep-alive 10s
        timeout check   10s
        maxconn         8000

listen admin_status
       bind 0.0.0.0:4001
       mode    http
       stats   uri       /stats
       stats   realm "HAProxy statistics"
       stats auth admin:admin123
      
listen mysql_proxy
       bind 0.0.0.0:4002
        mode    tcp
        balance roundrobin
        option  tcplog
        server  mycat01 192.168.56.11:8066 check port 8066 maxconn 2000 inter 5000 rise 2 fall 3
        server  mycat02 192.168.56.11:8067 check port 8067 maxconn 2000 inter 5000 rise 2 fall 3
       
       
#创建容器
docker create --name=haproxy --net host -v /data/haproxy:/usr/local/etc/haproxy haproxy

#启动容器
docker start haproxy && docker logs -f haproxy

#访问管理界面
http://192.168.56.11:4001/stats

 

7.PXC集群

7.1简介

Percona XtraDB Cluster是MySQL高可用性和可扩展性的解决方案,Percona XtraDB Cluster提供的特性如下:

1).同步复制,事务要么在所有节点提交或不提交。

2).多主复制,可以在任意节点进行写操作。

3).在从服务器上并行应用事件,真正意义上的并行复制。

4).节点自动配置。

5).数据一致性,不再是异步复制。

Percona XtraDB Cluster完全兼容MySQL和Percona Server,表现在:

1).数据的兼容性

2).应用程序的兼容性:无需更改应用程序

1).集群是有节点组成的,推荐配置至少3个节点,但是也可以运行在2个节点上

2).每个节点都是普通的mysql/percona服务器,可以将现有的数据库服务器组成集群,反之,也可以将集群拆分成单独的服务器。

3).每个节点都包含完整的数据副本

7.2优劣势对比

7.2.1优势

1).当执行一个查询时,在本地节点上执行。因为所有数据都在本地,无需 远程访问

2).无需集中管理。可以在任何时间点失去任何节点,但是集群将照常工作, 不受影响

3).良好的读负载扩展,任意节点都可以查询

7.2.2劣势

1).加入新节点,开销大。需要复制完整的数据

2).不能有效的解决写缩放问题,所有的写操作都将发生在所有节点上

3).有多少个节点就有多少重复的数据

7.3架构图

PXC集群主要由两部分组成:Percona Server with XtraDB和Write Set Replication patches(使用了Galera library,一个通用的用于事务型应用的同步、多主复制插件)

 

7.4回顾CAP理论

CAP理论作为分布式系统的基础理论,它描述的是一个分布式系统在以下三个特性中:

- 一致性(Consistency):指的分布式系统中的某个节点或者网络分区出现了故障的时候,整个系统仍然能对外提供满足一致性和可用性的服务。也就是说部分故障不影响整体使用。事实上我们在设计分布式系统是都会考虑到bug,硬件,网络等各种原因造成的故障,所以即使部分节点或者网络出现故障,我们要求整个系统还是要继续使用的(不继续使用,相当于只有一个分区,那么也就没有后续的一致性和可用性了)
- 可用性(Availability):一直可以正常的做读写操作。简单而言就是客户端一直可以正常访问并得到系统的正常响应。用户角度来看就是不会出现系统操作失败或者访问超时等问题。
- 分区容错性(Partition tolerance):在分布式系统完成某写操作后任何读操作,都应该获取到该写操作写入的那个最新的值。相当于要求分布式系统中的各节点时时刻刻保持数据的一致性。

最多满足其中的两个特性。也就是下图所描述的。分布式系统要么满足CA,要么CP,要么AP。无法同时满足CAP。

 

7.5PXC与Replication的区别

1)MySQL Replication: 可用性和分区容忍性
2)Percona XtraDB Cluster: 一致性和可用性
因此MySQL Replication并不保证数据的一致性,而Percona XtraDB Cluster提供数据一致性

1PXC集群方案所有节点都是可读写的,Replication从节点不能写入,因为主从同步是单向的,无法从slave节点向master节点同步。
2PXC同步机制是同步进行的,这也是它能保证数据强一致性的根本原因,Replication同步机制是异步进行的,它如果从节点停止同步,依然可以向主节点插入数据,正确返回,可能会造成数据主从的不一致性。
3PXC是牺牲性能保证数据一致性的,Replication在性能上是高于PXC的。所以两者用途也不一致。PXC是用于重要信息的存储,例如:订单、用户信息等;Replication用于一般信息的存储,能容忍数据丢失,例如:购物车、用户行为日志等。

7.6PXC部署

7.6.1集群规划

节点

端口

容器名称

数据卷

node1

13306

pxc-node1

v1

node2

13307

pxc-node2

v2

node3

13308

pxc-node3

v3

 

7.6.2集群部署

#创建数据卷(存储路径:/usr/lib/docker/volumes)
docker volume create v1
docker volume create v2
docker volume create v3
#拉取镜像
docker pull percona/percona-xtradb-cluster:5.7
docker tag percona/percona-xtradb-cluster:5.7 pxc
#创建网络
docker network create --subnet=172.30.0.0/24 pxc-network

#创建容器
#第一节点
docker create -p 13306:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc --name=pxc_node1 --net=pxc-network --ip=172.30.0.2 pxc
#第二节点(增加了CLUSTER_JOIN参数)
docker create -p 13307:3306 -v v2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc --name=pxc_node2 -e CLUSTER_JOIN=pxc_node1 --net=pxc-network --ip=172.30.0.3 pxc
#第三节点(增加了CLUSTER_JOIN参数)
docker create -p 13308:3306 -v v3:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc --name=pxc_node3 -e CLUSTER_JOIN=pxc_node1 --net=pxc-network --ip=172.30.0.4 pxc
#需要注意的是:先启动第一个节点,等到mysql客户端可以连接到服务器之后,再启动其它节点
docker start pxc_node1 && docker logs -f pxc_node1
docker start pxc_node2 && docker logs -f pxc_node2
docker start pxc_node3 && docker logs -f pxc_node3
#查看集群节点
show status like 'wsrep_cluster%'

7.6.3测试

#可在任意一个节点进行操作
create table `tb_user`(
`id` bigint(20) not null auto_increment,
`type` int(10) default null,
`title` varchar(100) default null,
primary key(`id`)
) ENGINE=INNODB auto_increment=1 default charset=utf8;

insert into `tb_user`(`id`,`type`,`title`) values('1','1','www.baidu.com');
insert into `tb_user`(`id`,`type`,`title`) values('2','7','www.baidu.com');
insert into `tb_user`(`id`,`type`,`title`) values('3','5','www.baidu.com');insert into `TB_USER`(`id`,`type`,`title`) values('4','2','www.baidu.com');

7.6.4集群说明

1)尽可能的控制PXC集群的规模,节点越多,数据同步速度就越慢
2)所有PXC节点的硬件配置要一致,如果不一致,配置低的节点将拖慢数据同步速度
3PXC集群只能支持Innodb引擎,不支持其他的存储引擎。

8综合应用

前面学习了主从架构、mycat中间件、haproxy负载均衡、PXC集群架构,在实际的项目中,往往不单单是一种架构,更多的使用是混合架构,下面我们模拟一种混合架构的方式完善数据库的集群,操作之前,请清理前面的所有docker。

8.1架构

 

说明:
1HAProxy作为负载均衡器
2)部署2mycat节点作为数据库中间件
3)部署了2PXC集群节点,作为2mycat分片,每个PXC集群中有2个节点,作为数据的同步存储。
4)部署了1个主从复制集群
5)非丢失性数据保存至PXC分片,其余数据保存至主从数据库中。

8.2部署PXC集群

6.2.1集群规划

集群1:

节点

端口

容器名称

数据卷

node1

13306

pxc-node1

zjs-v1

node2

13307

pxc-node2

zjs-v2

集群2:

节点

端口

容器名称

数据卷

node3

13308

pxc-node3

zjs-v3

node4

13309

pxc-node4

zjs-v4

8.2.2集群PXC部署

#创建数据卷(存储路径:/usr/lib/docker/volumes)
docker volume create zjs-v1
docker volume create zjs-v2
docker volume create zjs-v3
docker volume create zjs-v4

#拉取镜像
docker pull percona/percona-xtradb-cluster:5.7
docker tag percona/percona-xtradb-cluster:5.7 pxc

#创建网络
docker network create --subnet=172.30.0.0/24 pxc-network

#==========PXC集群1===================
#1节点
docker create -p 13306:3306 -v zjs-v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc --name=pxc_node1 --net=pxc-network --ip=172.30.0.2 pxc
#2节点(增加了CLUSTER_JOIN参数)
docker create -p 13307:3306 -v zjs-v2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc --name=pxc_node2 -e CLUSTER_JOIN=pxc_node1 --net=pxc-network --ip=172.30.0.3 pxc
#启动集群(先启动第一个节点)
docker start pxc_node1 && docker logs -f pxc_node1
docker start pxc_node2 && docker logs -f pxc_node2
#查看集群节点
show status like 'wsrep_cluster%'


#==========PXC集群2===================
#1节点
docker create -p 13308:3306 -v zjs-v3:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc --name=pxc_node3 --net=pxc-network --ip=172.30.0.4 pxc
#2节点(增加了CLUSTER_JOIN参数)
docker create -p 13309:3306 -v zjs-v4:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e CLUSTER_NAME=pxc --name=pxc_node4 -e CLUSTER_JOIN=pxc_node3 --net=pxc-network --ip=172.30.0.5 pxc
#启动集群(先启动第一个节点)
docker start pxc_node3 && docker logs -f pxc_node3
docker start pxc_node4 && docker logs -f pxc_node4
#查看集群节点
show status like 'wsrep_cluster%'

8.3部署主从集群

6.3.1集群规划

节点

端口

容器名称

数据卷

node5

23306

percona-master01

/data/mysql/master01

node6

23307

percona-slave01

/data/mysql/slave01

8.3.2集群部署

#==========创建主库==========
#创建目录
mkdir -p /data/mysql/master01
cd /data/mysql/master01
mkdir conf data
chmod -R 7777 *

#创建配置文件
vi /data/mysql/master01/conf/my.cnf

#输入以下内容
[mysqld]
log-bin=mysql-bin
server-id=1
lower_case_table_names=1

#创建容器
docker create --name percona-master01 -v /data/mysql/master01/data:/var/lib/mysql -v /data/mysql/master01/conf:/etc/my.cnf.d -p 23306:3306 -e MYSQL_ROOT_PASSWORD=root percona

#启动
docker start percona-master01 && docker logs -f percona-master01

#创建同步账户以及授权
create user 'backup'@'%' identified by '123';
grant replication slave on *.* to 'backup'@'%';
flush privileges;

#查看master状态
SHOW MASTER STATUS;
#查看二进制日志相关的配置项
SHOW GLOBAL VARIABLES LIKE 'binlog%';
#查看server相关的配置项
SHOW GLOBAL VARIABLES LIKE 'server%';


#==========创建从库==========
#创建目录
mkdir -p /data/mysql/slave01
cd /data/mysql/slave01
mkdir conf data
chmod -R 7777 *

#创建配置文件
vi /data/mysql/slave01/conf/my.cnf

#输入以下内容
[mysqld]
log-bin=mysql-bin
server-id=2
lower_case_table_names=1

#创建容器
docker create --name percona-slave01 -v /data/mysql/slave01/data:/var/lib/mysql -v /data/mysql/slave01/conf:/etc/my.cnf.d -p 23307:3306 -e MYSQL_ROOT_PASSWORD=root percona

#启动
docker start percona-slave01 && docker logs -f percona-slave01

#设置master相关信息
CHANGE MASTER TO
MASTER_HOST='192.168.56.11',
MASTER_USER='backup',
MASTER_PASSWORD='123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=743;

#启动同步
START SLAVE;

#查看master状态
show slave status;

8.4部署mycat集群

8.4.1集群规划

节点

端口

mycat01

18067

mycat02

28067

8.4.2集群部署

节点1:

#========Mycat01=========
cd /data
tar -xvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
cp -r /data/mycat /data/mycat01
cd /data/mycat01

#修改配置文件
vi /data/mycat01/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
        <system>
                <property name="nonePasswordLogin">0</property>
                <property name="useHandshakeV10">1</property>
                <property name="useSqlStat">0</property>
                <property name="useGlobleTableCheck">0</property>
                <property name="sequnceHandlerType">2</property>
                <property name="subqueryRelationshipCheck">false</property>
                <property name="processorBufferPoolType">0</property>
                <property name="handleDistributedTransactions">0</property>
                <property name="useOffHeapForMerge">1</property>
                <property name="memoryPageSize">64k</property>
                <property name="spillsFileBufferSize">1k</property>
                <property name="useStreamOutput">0</property>
                <property name="systemReserveMemorySize">384m</property>
                <property name="useZKSwitch">false</property>
        </system>
        <user name="zjs" defaultAccount="true">
                <property name="password">123</property>
                <property name="schemas">zjs</property>
        </user>
</mycat:server>

vi /data/mycat01/conf/schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 配置数据表,不同表访问不同数据库 -->
        <schema name="zjs" checkSQLschema="true" sqlMaxLimit="100">
                <table name="tb_user" dataNode="dn1,dn2" rule="mod-long" />
                <table name="tb_ad" dataNode="dn3" />
        </schema>
    <!-- 配置分片关系 -->
        <dataNode name="dn1" dataHost="cluster1" database="zjs" />
        <dataNode name="dn2" dataHost="cluster2" database="zjs" />
        <dataNode name="dn3" dataHost="cluster3" database="zjs" />
    <!-- 配置PXC1连接信息 balance=2:所有节点可读写 -->
        <dataHost name="cluster1" maxCon="1000" minCon="10" balance="2"
                          writeType="1" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="w1" url="192.168.56.11:13306" user="root" password="root">
                        <readHost host="w1r1" url="192.168.56.11:13307" user="root" password="root" />
                </writeHost>
        </dataHost>
    <!-- 配置PXC2连接信息 balance=2:所有节点可读写-->
        <dataHost name="cluster2" maxCon="1000" minCon="10" balance="2"
                          writeType="1" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="w1" url="192.168.56.11:13308" user="root" password="root">
                        <readHost host="w1r1" url="192.168.56.11:1339" user="root" password="root" />
                </writeHost>
        </dataHost>
    <!-- 配置主从连接信息 balance=3:读写分离-->
        <dataHost name="cluster3" maxCon="1000" minCon="10" balance="3"
                          writeType="1" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
                <heartbeat>select user()</heartbeat>
                <writeHost host="w1" url="192.168.56.11:23306" user="root" password="root">
                        <readHost host="w1r1" url="192.168.56.11:23307" user="root" password="root" />
                </writeHost>
        </dataHost>
</mycat:schema>

vi /data/mycat01/conf/rule.xml

        <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- how many data nodes -->
                <property name="count">2</property>
        </function>
       
#设置JMX端口    
vi wrapper.conf   
wrapper.java.additional.9=-Dcom.sun.management.jmxremote.port=11985
#设置服务端口
vi server.xml
<property name="serverPort">18067</property>
<property name="managerPort">19067</property>
#启动验证
./mycat console

vi startup_nowrap.sh
:set ff=unix
:wq
#启动
./startup_nowrap.sh

节点2:

#========Mycat02=========
cd /data
#复制mycat01的内容
cp -r /data/mycat01 /data/mycat02
cd /data/mycat02

#设置JMX端口
vi wrapper.conf   
wrapper.java.additional.9=-Dcom.sun.management.jmxremote.port=21985
#设置服务端口
vi server.xml
<property name="serverPort">28067</property>
<property name="managerPort">29067</property>
#启动验证
./mycat console
vi startup_nowrap.sh
:set ff=unix
:wq
#启动
./startup_nowrap.sh

8.5部署HAProxy

#拉取镜像
docker pull docker.io/haproxy

#创建目录,用于存放配置文件
mkdir -p /data/haproxy
vi /data/haproxy/haproxy.cfg

global
        maxconn         10000
        log             127.0.0.1 local0
        daemon
defaults
        mode            http
        log             global
        option          httplog
        option          dontlognull
        option http-server-close
        option forwardfor except 127.0.0.0/8
        option          redispatch
        retries         3
        timeout http-request 10s
        timeout queue   30s
        timeout connect 5s
        timeout client  30s
        timeout server  30s
        timeout http-keep-alive 10s
        timeout check   10s
        maxconn         8000

listen admin_status
       bind 0.0.0.0:4001
       mode    http
       stats   uri       /stats
       stats   realm "HAProxy statistics"
       stats auth admin:admin123
      
listen mysql_proxy
       bind 0.0.0.0:4002
        mode    tcp
        balance roundrobin
        option  tcplog
        server  mycat01 192.168.56.11:18067 check port 18067 maxconn 2000 inter 5000 rise 2 fall 3
        server  mycat02 192.168.56.11:28067 check port 28067 maxconn 2000 inter 5000 rise 2 fall 3
           
#创建容器
docker create --name=haproxy --net host -v /data/haproxy:/usr/local/etc/haproxy haproxy

#启动容器
docker start haproxy && docker logs -f haproxy

#访问管理界面
http://192.168.56.11:4001/stats

至此,一套完整的综合应用数据库部署已完成。当然,MYSQL集群的演化过程不止这一种,结合不同的组件,可以演化出适合自身的架构来。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值