Mycat之——实现MySQL垂直分库

数据库架构演化

对于一个早期的商城系统来说,由于业务量不太大,数据承载压力不高,我们可以将所有的数据放在一台MySQL服务器上,此时的数据库架构就类似于下图所示。

在这里插入图片描述

随着业务量的不断增加,数据库的压力越来越大,此时我们可以将MySQL做成主从复制集群,使用Mycat完成MySQL的读写分离,其中,MySQL主库作为写库,MySQL从库作为读库,此时的数据库架构可以如下图所示,

在这里插入图片描述

关于Mycat如何实现MySQL读写分离,大家可以参考《Mycat之——Mycat在MySQL主从复制基础上实现读写分离》一文。

又过了一段时间,随着业务量的上涨,我们发现对于商城业务来说,不同的业务所承受的压力不同,访问的频次也是有区别的。此时,我们就会思考能否将商城中不同的业务的数据独立出来,做成单独的数据库,并且对于上层的应用程序来说,访问这些数据库时,仍旧像访问同一个数据库一样。此时,我们就会想到数据库的垂直切分。

我们可以将商城数据库分为用户数据库、商品数据库、订单数据库和仓配数据库。由于在商城业务中,订单业务和仓配业务需要时刻进行交互,前期,我们就可以将订单业务和仓配业务的数据库合并为一个数据库。最终,我们可以将商城业务划分为用户业务、商品业务和订单业务。

此时,我们的商城数据库架构可以如下图所示。

在这里插入图片描述

其中,对于上图中的每一部分,我们都可以做成高可用模式,有关高可用模式大家可以参考如下文章。

Mycat之——Mycat在MySQL主从复制基础上实现读写分离

Mycat之——Mycat集群部署(基于HAProxy + Mycat)

Mycat之——高可用负载均衡集群的实现(HAProxy + Keepalived + Mycat)

本文,我们就基于一个简单的商城数据库来实现MySQL的垂直分库。

服务器规划

我们可以将服务器的规划简化成下面的表格所示。

主机名 IP地址 安装的服务 业务数据库
binghe151 192.168.175.151 Mycat shop(虚拟库)
binghe152 192.168.175.152 MySQL order_db(实体订单库)
binghe153 192.168.175.153 MySQL product_db(实体商品库)
binghe154 192.168.175.154 MySQL customer_db(实体用户库)

安装MySQL

如果需要安装MySQL 8.x版本,则可以参考《MySQL之——源码编译MySQL8.x+升级gcc+升级cmake(亲测完整版)

如果需要安装MySQL 5.x版本,则可以参考《MySQL之——CentOS6.5 编译安装MySQL5.6或5.7

我这里,安装的是MySQL 8.x版本。安装其他的版本也可以。

创建实体数据库

  • 创建order_db库

在binghe152服务器上创建订单库,SQL语句如下所示。

create database if not exists order_db;
  • 创建product_db库

在binghe153服务器上创建商品库,SQL语句如下所示。

create database if not exists product_db;
  • 创建customer_db库

在binghe154服务器上创建用户库,SQL语句如下所示。

create database if not exists customer_db;

有关各数据库的数据导入,大家可以下载【商城数据库SQL脚本文件.rar】文件,解压后,分别导入到相应的数据库即可。

创建Mycat连接MySQL的用户

分别在三个MySQL数据库中创建Mycat连接MySQL的用户,如果大家安装的是MySQL 8.x版本,则在MySQL命令行执行如下命令

CREATE USER 'mycat'@'192.168.175.%' IDENTIFIED BY 'mycat';
ALTER USER 'mycat'@'192.168.175.%' IDENTIFIED WITH mysql_native_password BY 'mycat'; 
GRANT SELECT, INSERT, UPDATE, DELETE  ON *.* TO 'mycat'@'192.168.175.%';
FLUSH PRIVILEGES;

如果大家安装的是MySQL 5.x版本,则在MySQL命令行执行如下命令。

GRANT SELECT, INSERT, UPDATE, DELETE  ON *.* TO 'mycat'@'192.168.175.%' IDENTIFIED BY 'mycat';
FLUSH PRIVILEGES;

下载并安装Mycat

我这里,下载的是Mycat的1.6.7.4 release版本,连接地址为:http://dl.mycat.io/1.6.7.4/ 。 下载后直接解压到binghe151服务器的/usr/local/mycat目录下即可。

这里,需要注意的是,Mycat是使用Java语言编写的,所以安装Mycat时,需要安装JDK,大家可以按照如下方式安装JDK

到JDK官网下载JDK 1.8版本,JDK1.8的下载地址为:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

我这里下载的JDK安装包版本为:jdk-8u212-linux-x64.tar.gz,如果JDK版本已更新,读者下载对应的版本即可。

将下载的JDK安装包解压到/usr/local/jdk1.8.0_212目录下。并配置JDK和Mycat的系统环境变量,如下所示。

vim /etc/profile
MYCAT_HOME=/usr/local/mycat
JAVA_HOME=/usr/local/jdk1.8.0_212
CLASS_PATH=.:$JAVA_HOME/lib
PATH=$JAVA_HOME/bin:$MYCAT_HOME/bin:$PATH
export JAVA_HOME MYCAT_HOME CLASS_PATH PATH

使系统环境变量生效,如下所示。

source /etc/profile

由于Mycat垂直分库不需要配置Mycat的分片规则,也就不需要配置rule.xml文件,此时只需要配置schema.xml文件和server.xml文件。

配置schema.xml文件

编辑后的schema.xml文件内容如下所示。

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

	<schema name="shop" checkSQLschema="false" sqlMaxLimit="1000">
		<table name="order_master" primaryKey="order_id" dataNode = "ordb"/>
		<table name="order_detail" primaryKey="order_detail_id" dataNode = "ordb"/>
		<table name="order_cart" primaryKey="cart_id" dataNode = "ordb"/>
		<table name="order_customer_addr" primaryKey="customer_addr_id" dataNode = "ordb"/>
		<table name="region_info" primaryKey="region_id" dataNode = "ordb,prodb,custdb" type="global"/>
		<table name="serial" primaryKey="id" dataNode = "ordb"/>
		<table name="shipping_info" primaryKey="ship_id" dataNode = "ordb"/>
		<table name="warehouse_info" primaryKey="w_id" dataNode = "ordb"/>
		<table name="warehouse_proudct" primaryKey="wp_id" dataNode = "ordb"/>
		
		<table name="product_brand_info" primaryKey="brand_id" dataNode = "prodb"/>
		<table name="product_category" primaryKey="category_id" dataNode = "prodb"/>
		<table name="product_comment" primaryKey="comment_id" dataNode = "prodb"/>
		<table name="product_info" primaryKey="product_id" dataNode = "prodb"/>
		<table name="product_pic_info" primaryKey="product_pic_id" dataNode = "prodb"/>
		<table name="product_supplier_info" primaryKey="supplier_id" dataNode = "prodb"/>
		
		<table name="customer_balance_log" primaryKey="balance_id" dataNode = "custdb"/>
		<table name="customer_inf" primaryKey="customer_inf_id" dataNode = "custdb"/>
		<table name="customer_level_inf" primaryKey="customer_level" dataNode = "custdb"/>
		<table name="customer_login" primaryKey="customer_id" dataNode = "custdb"/>
		<table name="customer_login_log" primaryKey="login_id" dataNode = "custdb"/>
		<table name="customer_point_log" primaryKey="point_id" dataNode = "custdb"/>
		
	</schema>
	 
	<dataNode name="ordb" dataHost="binghe152" database="order_db" />
	<dataNode name="prodb" dataHost="binghe153" database="product_db" />
	<dataNode name="custdb" dataHost="binghe154" database="customer_db" />

	
	<dataHost name="binghe152" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="binghe52" url="192.168.175.152:3306" user="mycat" password="mycat"/>
	</dataHost>
	
	<dataHost name="binghe153" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="binghe53" url="192.168.175.153:3306" user="mycat" password="mycat"/>
	</dataHost>
	
	<dataHost name="binghe154" maxCon="1000" minCon="10" balance="1"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<writeHost host="binghe54" url="192.168.175.154:3306" user="mycat" password="mycat"/>
	</dataHost>
	
</mycat:schema>

由于地域信息表region_info在每个业务库中可能都需要使用到,此时,我们可以将地域信息表region_info配置成全局表,将其配置到每个业务库中。

如下所示。

<table name="region_info" primaryKey="region_id" dataNode = "ordb,prodb,custdb" type="global"/>

另外,还需要在每个实体业务库中,创建地域信息表region_info,并将数据导入到region_info表。此时,通过Mycat管理region_info表时,数据会分别同步到每个业务数据库中。

注意:当将某个数据表在Mycat中配置成全局表时,只有通过Mycat对这个表进行增加、删除和修改操作时,数据才会同步到每个实体数据库中。

配置server.xml文件

编辑后的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="useHandshakeV10">1</property>
         <property name="defaultSqlParser">druidparser</property>
		<property name="serverPort">3307</property>
		<property name="managerPort">3308</property>
		<property name="nonePasswordLogin">0</property>
		<property name="bindIp">0.0.0.0</property>
		<property name="charset">utf8mb4</property>
		<property name="frontWriteQueueSize">2048</property>
		<property name="txIsolation">2</property>
		<property name="processors">2</property>
		<property name="idleTimeout">1800000</property>
		<property name="sqlExecuteTimeout">300</property>
		<property name="useSqlStat">0</property>
		<property name="useGlobleTableCheck">0</property>
		<property name="sequenceHandlerType">2</property>
		<property name="defaultMaxLimit">1000</property>
		<property name="maxPacketSize">104857600</property>
	</system>
	
	<user name="mycat" defaultAccount="true">
		<property name="usingDecrypt">1</property>
		<property name="password">cTwf23RrpBCEmalp/nx0BAKenNhvNs2NSr9nYiMzHADeEDEfwVWlI6hBDccJjNBJqJxnunHFp5ae63PPnMfGYA==</property>
		<property name="schemas">shop</property>
	</user>
</mycat:server>

其中,在server.xml中,使用了Mycat对密码的加密功能。user标签下的password标签的值为登录Mycat的密码,此值使用Mycat提供的加密类对密码明文进行了加密。此类存在于Mycat安装目录下的lib目录下的Mycat-server-xxx-release.jar中的io.mycat.util.DecryptUtil类,可以使用如下命令对密码进行加密。

java java -cp /usr/local/mycat/lib/Mycat-server-xxx-release.jar io.mycat.util.DecryptUtil 0:mycat:mycat

其中0:mycat:mycat为运行Jar包的参数,0表示应用程序连接Mycat时使用密文密码;第一个mycat代表连接Mycat的用户名,也就是说为哪个用户的密码加密;第二个mycat代表需要加密的密码。

加密后的结果数据如下所示

cTwf23RrpBCEmalp/nx0BAKenNhvNs2NSr9nYiMzHADeEDEfwVWlI6hBDccJjNBJqJxnunHFp5ae63PPnMfGYA==

即user标签下的password属性的值。

如果按照上述方式为连接Mycat的密码加密后,需要在user标签下配置如下选项,否则无法正确连接Mycat。

<property name="usingDecrypt">1</property>

另外,在需要使用MySQL 8.x的mysql命令连接Mycat时,在server.xml文件的system标签下必须配置如下选项。

<property name="useHandshakeV10">1</property>
<property name="defaultSqlParser">druidparser</property>

否则,MySQL 8.x的mysql命令连接Mycat会失败。

连接Mycat

使用MySQL 8.x中的mysql命令连接Mycat,如下所示。

[root@binghe151 ~]# mysql -umycat -pmycat -h192.168.175.151 -P3307 --default-auth=mysql_native_password
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.29-mycat-xxx-release-20200228205020 MyCat Server (OpenCloudDB)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

使用MySQL8.x中的mysql命令连接Mycat时,需要注意的是要在mysql命令后面添加–default-auth=mysql_native_password选项。如果使用的是MySQL 5.x的mysql命令行,则不需要在命令后面添加–default-auth=mysql_native_password选项。

接下来,查看下Mycat下的逻辑库和逻辑表,如下所示。

mysql> SHOW DATABASES;
+----------+
| DATABASE |
+----------+
| shop     |
+----------+
1 row in set (0.00 sec)

mysql> USE shop;
Database changed
mysql> SHOW TABLES;
+-----------------------+
| Tables in shop        |
+-----------------------+
| customer_balance_log  |
| customer_inf          |
| customer_level_inf    |
| customer_login        |
| customer_login_log    |
| customer_point_log    |
| order_cart            |
| order_customer_addr   |
| order_detail          |
| order_master          |
| product_brand_info    |
| product_category      |
| product_comment       |
| product_info          |
| product_pic_info      |
| product_supplier_info |
| region_info           |
| serial                |
| shipping_info         |
| warehouse_info        |
| warehouse_proudct     |
+-----------------------+
21 rows in set (0.00 sec)

mysql> SELECT product_id, product_code, product_name FROM product_info LIMIT 10;
+------------+------------------+---------------------------------------+
| product_id | product_code     | product_name                          |
+------------+------------------+---------------------------------------+
|          1 | 3700000000000001 | [Columbia]打底裤示例商品-1            |
|          2 | 3600000000000001 | [TheNorthFace]小脚裤示例商品-1        |
|          3 | 3500000000000001 | [李宁]九分裤示例商品-1                |
|          4 | 3400000000000001 | [LOWA]哈伦裤示例商品-1                |
|          5 | 3300000000000001 | [JACK&JONES]连体裤示例商品-1          |
|          6 | 3200000000000001 | [诺诗兰]牛仔裤示例商品-1              |
|          7 | 3100000000000001 | [骆驼]休闲裤示例商品-1                |
|          8 | 3000000000000001 | [金狐狸]风衣示例商品-1                |
|          9 | 2900000000000001 | [Columbia]小西装示例商品-1            |
|         10 | 2800000000000001 | [李宁]外套示例商品-1                  |
+------------+------------------+---------------------------------------+
10 rows in set (0.01 sec)

至此,就完成了基于Mycat对MySQL的垂直分库操作。

发布了1322 篇原创文章 · 获赞 2046 · 访问量 518万+

猜你喜欢

转载自blog.csdn.net/l1028386804/article/details/104592724