MyCat 之垂直分库实战
一)垂直分库
什么是垂直切分?通俗的讲就是将我们的数据库按照模块划分成不同的数据库,以此来解决数据库访问的压力。例如,下面的案例将会把原始包含订单,用户,商品,仓配等信息的数据库划分为订单库,用户库,商品库三个数据库。但实际访问还是相当于访问一个数据库一样,这里就需要借助我们的MyCat来配置逻辑数据库了
如果是在实际线上,若是为了保证在作垂直分库的时候不受影响,前一步我们需要完成各个节点的主从同步工作,这样之后做了分库,切换访问mycat,才能保证数据不会错乱。关于mysql的主从同步可以详细看【Mysql 主从复制实战】
1)首先看一下我们的环境
所以在演示如何具体的划分之前,需要按照上面的准备好我们演示环境
2)因为我们这次只是演示数据库的垂直分库,所以只是涉及到了MyCat的【schema.xml】和【server.xml】,并不会用到【rule.xml】,所以这里指出可以将关注重点放在【schema.xml】和【server.xml】两个文件上面
3)创建我们连接mycat的用户并授权,在我们配置【schema.xml】的时候需要用到
create user aaa@qq.com'192.168.124.%' identified by '123456';
grant select,insert,update,delete on *.* to aaa@qq.com'192.168.124.%';
4)下面就是配置我们的【schema.xml】
上面是我们原始数据库的所有表,现在要做一个垂直的拆分,按照我们上面所说需要分成三个库,下面看我们的详细配置
打开【shcema.xml】,下面是详细的配置
<schema name="mycat_db" checkSQLschema="false" sqlMaxLimit="100">
<table name="order_master" primarykey="order_id" dataNode="orderDB" />
<table name="order_detail" primarykey="order_detail_id" dataNode="orderDB" />
<table name="order_cart" primarykey="cart_id" dataNode="orderDB" />
<table name="order_customer_addr" primarykey="customer_addr_id" dataNode="orderDB" />
<table name="region_info" primarykey="region_id" dataNode="orderDB" />
<table name="shipping_info" primarykey="ship_id" dataNode="orderDB" />
<table name="warehouse_info" primarykey="w_id" dataNode="orderDB" />
<table name="warehouse_proudct" primarykey="wp_id" dataNode="orderDB" />
<table name="product_brand_info" primarykey="brand_id" dataNode="productDB" />
<table name="product_category" primarykey="category_id" dataNode="productDB" />
<table name="product_comment" primarykey="comment_id" dataNode="productDB" />
<table name="product_info" primarykey="product_id" dataNode="productDB" />
<table name="product_supplier_info" primarykey="supplier_id" dataNode="productDB" />
<table name="product_pic_info" primarykey="product_pic_id" dataNode="productDB" />
<table name="customer_balance_log" primarykey="balance_id" dataNode="customerDB" />
<table name="customer_inf" primarykey="customer_inf_id" dataNode="customerDB" />
<table name="customer_level_inf" primarykey="customer_level" dataNode="customerDB" />
<table name="customer_login" primarykey="customer_id" dataNode="customerDB" />
<table name="customer_login_log" primarykey="login_id" dataNode="customerDB" />
<table name="customer_point_log" primarykey="point_id" dataNode="customerDB" />
</schema>
<dataNode name="orderDB" dataHost="mysql39" database="order_db" />
<dataNode name="productDB" dataHost="mysql40" database="product_db" />
<dataNode name="customerDB" dataHost="mysql41" database="customer_db" />
<dataHost name="mysql39" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.124.39" url="192.168.124.39:3306" user="mycat" password="123456"/>
</dataHost>
<dataHost name="mysql40" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.124.40" url="192.168.124.40:3306" user="mycat" password="123456"/>
</dataHost>
<dataHost name="mysql41" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.124.41" url="192.168.124.41:3306" user="mycat" password="123456"/>
</dataHost>
5)配置我们的【server.xml】
<system>
<property name="serverPort">8066</property>
<property name="managerPort">9066</property>
<property name="nonePasswordLogin">0</property>
<property name="bindIp">0.0.0.0</property>
<property name="frontWriteQueueSize">2048</property>
<property name="charset">utf-8</property>
<property name="txIsolation">2</property>
<property name="processors">8</property>
<property name="idleTimeout">300000</property>
<property name="sqlExecuteTimeout">300</property>
<property name="useSqlStat">0</property>
<property name="useGlobleTableCheck">0</property>
<property name="defaultMaxLimit">100</property>
<property name="maxPacketSize">104857600</property>
</system>
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">mycat_db</property>
</user>
接下来我们便可以使用【root】用户去登陆mycat了,这里注意:
<property name="schemas">mycat_db</property> 的mycat_db 一定要和我们【schema.xml】中的schema头 name的名字一致
6)在我们任意一个数据库节点登陆进行验证
我们使用【mysql_node4】去验证
mysql -uroot -p123456 -P8066 -h192.168.124.38
登陆成功,然后看一下我们的数据库,只有我们配置的一个逻辑数据库【mycat_db】,查看一下表,显示了原始数据库的所有表,具体如下图:
至此我们的mycat垂直分库基本配置完毕。
7)简单总结一下垂直分库的优缺点
优点:
1)数据库的拆分简单明了,拆分规则明确
2)应用程序模块清晰明确,整合容易
3)数据维护方便,容易定位
缺点:
1)部分表关联无法在数据库级别完成,需要在程序中完成
2)对于访问极其频繁且数据量超大的表任然存在性能瓶颈
3)切分达到一定程度之后,扩展性会遇到限制
二)冗余数据清理
上面做分库之前都是做了主从同步的,所以虽然我们现在将原始数据库做了拆分,但是拆分之后还是有数据冗余的,现在每一份数据库都保留着最原始的所有数据库表,所以现在我们需要做一下删除冗余数据的处理
具体操作其实也很简单,
1)首先停止掉我们之前所有节点的主从同步机制
stop slave;
2)然后将对应模块的数据库中无用的表做一个删除处理,这里我直接使用客户端手动去删除就可以了。清理之后如下图:
三个数据库只是保留各自模块的表
3)验证
再次登陆我们的mycat
mysql -uroot -p123456 -P8066 -h192.168.124.38
查看对应的表
show tables;
还是我们配置的所有逻辑表,冗余数据删除成功
三)全局表的配置使用
为何要使用全局表?当我们在做两个模块的联合查询的时候,因为现在做了分库,无法通过关联的sql语句做查询,通常我们的解决方案会有以下三种:
1)使用Mycat的全局表
2)相关表中做冗余数据
3)使用API的方式获取数据
鉴于讲解mycat的使用,这里简单说一下mycat的全局表的配置
基本思路:
1)三个数据库中需要各自保持一份表数据
2)修改我们【schema.xml】的逻辑表的全局配置
这里我们使用节点2中 【region_info】表来做演示,这是一个省市的数据表
1)导出数据表
mysqldump -uroot -p order_db region_info > region_info;
2)分别将导出的表数据拷贝到节点3(192.168.124.40)和节点4(192.168.124.41)中
scp region_info aaa@qq.com:/root
scp region_info aaa@qq.com:/root
3)然后分别导入到各个数据库中
mysql -uroot -p product_db < region_info
mysql -uroot -p customer_db < region_info
4)修改我们【schema.xml】中的配置
<table name="region_info" primaryKey="region_id" dataNode="orderDB,productDB,customerDB" type="global"/>
5)再次启动我们的mycat
mycat start
再次关联查询数据就可以查到了。配置了全局表之后,我们的mycat就会来维护这个全局表的数据。
如何验证?
通过客户端连接mycat,修改全局表的数据,分别查看各个节点全局表数据有没有发生变化,变化了即表示全局表配置成功。
下一篇: 伍六七带你学算法——被忽视的数学公式