前言
接著上一篇文章:MyCat基礎知識
本文以實際操作為主,理論性比較少,主要包含mycat安裝,mysql主從復制,mycat垂直分庫,mycat水平分表等系列操作,希望對有機會接觸到mycat的朋友一些啟發。
mycat安裝
1、安裝mysql5.7并導入數據
使用Navicat導入以下數據。
shop_db.sql
2、下載并解壓mycat
wget http://dl.mycat.io/1.6.7.4/Mycat-server-1.6.7.4-release/Mycat-server-1.6.7.4-release-20200105164103-linux.tar.gz
3、安裝java7以上環境
此步驟各位可以網絡搜索,此處略過。
4、新建mycat運行系統賬號
adduser mycat
chown mycat:mycat -R mycat/
5、修改mycat啟動參數
在mycat的conf目錄下找到vi wrapper.conf
修改其中的運行內存為合適值,默認的是2G,最好是按照本機的情況來
wrapper.java.additional.4=-XX:MaxDirectMemorySize=512M
6、配置環境變量
vi /etc/profile
## 添加:
MYCAT_HOME=/usr/local/mycat
export PATH=${MYCAT_HOME}/bin:${PATH}
## 最后:
source /etc/profile ## 使環境變量生效
垂直分庫
1、分析數據表與業務之間的關系
首先對項目的業務需求要十分清晰,確定哪些模塊哪些表是否需要分庫,考慮表數據量是否很大,并發等問題,進而確定哪些表需要分庫分表。
下面是一個例子:
2、mysql主從數據庫復制
項目一開始往往是一個數據庫來弄的,隨著業務量特別大的時候才會考慮分庫分表。那么如何將原來的數據同步到另外一個新的數據庫呢,這就是接下來要說的mysql主從復制。
2.1、導出當前數據庫的數據
mysqldump --master-data=2 --single-transaction --routines --triggers --events -uroot -p order_db > bak_shop_db.sql
其中--master-data=2是為了記錄事務日志點。
如果遇到以下問題:
mysqldump: Error: Binlogging on server not active
解決方案:
vi /etc/my.cnf
在[mysqld]標簽下添加:
[mysqld]
log-bin=mysql-bin
server-id=1
2.2、將bak_shop_db.sql復制到其他的服務器
scp bak_shop_db.sql root@192.168.56.11:/root
scp bak_shop_db.sql root@192.168.56.12:/root
scp bak_shop_db.sql root@192.168.56.13:/root
2.3、導入數據
現以訂單order_db(192.168.56.11)為例:
在mysql命令行中導入
mysql -uroot -p -e"create database order_db"
mysql -uroot -p order_db < bak_shop_db.sql
2.4、創建同步用戶
建議添加一個同步用的用戶,這樣子比較安全點。
create user 'im_repl'@'192.168.56.%' identified by '123456';
grant replication slave on . to 'im_repl'@'192.168.56.%'
2.5、 在從數據庫服務建立復制鏈路
建立主從復制鏈路
change master to master_host='192.168.56.10',master_user='im_repl',master_password='123456',MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=154;
change replication filter replicate_rewrite_db=((shop_db,order_db))
其中的MASTER_LOG_FILE和MASTER_LOG_POS值在bak_shop_db.sql中,表示導出的時間點。因為你導出sql的時候,有可能主數據庫一直有數據增加,那么從數據庫開始復制應該從什么時候開始復制呢,所以這兩個參數的作用就是解決這個問題的。(這一小節的第1點是關鍵。)
如果從數據庫名和主數據庫名不一樣的話,可以考慮在從數據庫中運行:
change replication filter replicate_rewrite_db=((主數據庫名,從數據庫名))
2.6、啟動slave服務
在mysql命令行中輸入
start slave;
show slave status \G
可能遇到問題如下:
Slave_IO_Running: No ### 此處應該是Yes,才代表成功。
Slave_SQL_Running: Yes
啟動失敗,如果是以下錯誤:
Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
原因:檢查發現他們的auto.cnf中的server-uuid是一樣的。因為復制的mysql才會出現這種情況。
解決辦法:
vi /var/lib/mysql/auto.cnf
修改它的id值.
然后重啟mysql服務
systemctl restart mysqld
2.6、驗證是否主從同步。
在主庫(192.168.56.10)中修改數據,再看看從庫是否已經同步修改了。
update order_detail set product_name='迪奧999' where order_detail_id = 1;
至此,mysql的主從同步已經成功了!!! _
3、mycat垂直分庫配置
3.1、創建mycat用戶并賦予增刪改查的權限。
create user im_mycat@'192.168.56.%' identified by '123456';
grant select,insert,update,delete on . to im_mycat@'192.168.56.%';
3.2、配置schema.xml
關于配置文件的解析可以閱讀我的上一篇文章或者《mycat權威指南》
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="shop_db" checkSQLschema="false" sqlMaxLimit="100">
<table name="region_info" primaryKey="region_id" dataNode="orddb,custdb,prodb" type="global"/>
<table name="order_cart" primaryKey="cart_id" dataNode="orddb" />
<table name="order_customer_addr" primaryKey="customer_addr_id" dataNode="orddb" />
<table name="order_detail" primaryKey="order_detail_id" dataNode="orddb" />
<table name="order_master" primaryKey="order_id" dataNode="orddb" />
<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" />
<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_supplier_info" primaryKey="supplier_id" dataNode="prodb" />
</schema>
<dataNode name="orddb" dataHost="mysql11" database="order_db" />
<dataNode name="custdb" dataHost="mysql12" database="customer_db" />
<dataNode name="prodb" dataHost="mysql13" database="product_db" />
<dataHost name="mysql11" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.11" url="192.168.56.11:3306" user="im_mycat" password="123456" />
</dataHost>
<dataHost name="mysql12" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.12" url="192.168.56.12:3306" user="im_mycat" password="123456" />
</dataHost>
<dataHost name="mysql13" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.13" url="192.168.56.13:3306" user="im_mycat" password="123456" />
</dataHost>
</mycat:schema>
3.3、配置server.xml
關于配置文件的解析可以閱讀我的上一篇文章或者《mycat權威指南》
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<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">utf8</property>
<property name="txIsolation">2</property>
<property name="processors">8</property>
<property name="idleTimeout">1800000</property>
<property name="useSqlStat">0</property> <!-- 1為開啟實時統計、0為關閉 -->
<property name="useGlobleTableCheck">0</property> <!-- 1為開啟全加班一致性檢測、0為關閉 -->
<property name="sqlExecuteTimeout">300</property> <!-- SQL 執行超時 單位:秒-->
<property name="sequnceHandlerType">2</property>
<property name="defaultMaxLimit">100</property>
<property name="maxPacketSize">104857600</property>
</system>
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<!--只配置邏輯庫與schema的name值對應,對外-->
<property name="schemas">shop_db</property>
</user>
</mycat:server>
4、通過mycat訪問數據庫
mysql -uroot -p123456 -P8066 -h192.168.56.10
查看邏輯數據庫中的表的數據是否存在
5、刪除多余的數據表
5.1、需要停止原先的主從同步。
在mysql控制臺命令行輸入
show slave status \G
stop slave;
reset slave all;
show slave status \G
5.2、保留每個分庫的表,刪除其他多余的數據表。
比如:訂單庫可以刪除用戶和商品相關的表。
6、配置全局表
6.1、復制全局表到各個節點。
6.2、配置schema.xml
<table name="region_info" primaryKey="region_id" dataNode="orddb,custdb,prodb" type="global"/>
水平分表
1、確定需要水平切分的表
業務量特別大,數據隨著時間會越來越多數據的表,比如訂單表。
2、選擇合適分片鍵和分片算法
分片鍵(主鍵)選擇原則:
- 1、盡可能均勻分布在各個節點(盡量是唯一性);
- 2、查詢時使用最頻繁的或重要條件
分片算法選擇:
- 1、盡可能將數據均勻分布在各個節點
3、使用mycat水平分片
3.1、schema.xml配置邏輯庫和邏輯表
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="shop_db" checkSQLschema="false" sqlMaxLimit="100">
<table name="region_info" primaryKey="region_id" dataNode="orddb,custdb,prodb" type="global"/>
<table name="order_cart" primaryKey="cart_id" dataNode="orddb" />
<table name="order_customer_addr" primaryKey="customer_addr_id" dataNode="orddb" />
<table name="order_detail" primaryKey="order_detail_id" dataNode="orddb" />
<!-- 水平分片,分片規則(在rule.xml):order_master -->
<table name="order_master" primaryKey="order_id" dataNode="orddb01,orddb02,orddb03,orddb04" rule="order_master" />
<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" />
<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_supplier_info" primaryKey="supplier_id" dataNode="prodb" />
</schema>
<dataNode name="orddb" dataHost="mysql11" database="order_db" />
<dataNode name="custdb" dataHost="mysql12" database="customer_db" />
<dataNode name="prodb" dataHost="mysql13" database="product_db" />
<!-- 水平分片 -->
<dataNode name="orddb01" dataHost="mysql11" database="orddb01" />
<dataNode name="orddb02" dataHost="mysql11" database="orddb02" />
<dataNode name="orddb03" dataHost="mysql12" database="orddb01" />
<dataNode name="orddb04" dataHost="mysql13" database="orddb01" />
<dataHost name="mysql13" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.13" url="192.168.56.13:3306" user="im_mycat" password="123456" />
</dataHost>
<dataHost name="mysql11" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.11" url="192.168.56.11:3306" user="im_mycat" password="123456" />
</dataHost>
<dataHost name="mysql12" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.12" url="192.168.56.12:3306" user="im_mycat" password="123456" />
</dataHost>
</mycat:schema>
3.2、rule.xml配置分片規則
<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="order_master">
<rule>
<!-- 分片鍵customer_id -->
<columns>customer_id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">4</property>
</function>
</mycat:rule>
至此水平分表已經完成了80%,但是這里會有2個問題:
1、order_id如果是自增長的,那么現在就無法保證整體的order_id是唯一的。
2、如果order_master表與其他關聯表order_detail進行join操作是沒法實現的。
4、 配置全局自增長id
1、創建一個mycat數據庫,找到mycat的配置目錄中的dbseq.sql
然后導入
mysql -uroot -p mycat < dbseq.sql
2、接著需要修改server.xml中的sequnceHandlerType=1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<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">utf8</property>
<property name="txIsolation">2</property>
<property name="processors">8</property>
<property name="idleTimeout">1800000</property>
<property name="useSqlStat">0</property> <!-- 1為開啟實時統計、0為關閉 -->
<property name="useGlobleTableCheck">0</property> <!-- 1為開啟全加班一致性檢測、0為關閉 -->
<property name="sqlExecuteTimeout">300</property> <!-- SQL 執行超時 單位:秒-->
<property name="sequnceHandlerType">1</property> <!-- 全局id生成規則,1指的是使用數據庫的方式 -->
<property name="defaultMaxLimit">100</property>
<property name="maxPacketSize">104857600</property>
</system>
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<!--只配置邏輯庫,對外-->
<property name="schemas">shop_db</property>
</user>
</mycat:server>
3、找到mycat的配置文件sequence_db_conf.properties,增加配置如下:
#sequence stored in datanode
GLOBAL=mycat
ORDER_MASTER=mycat
4、需要在mycat數據庫的MYCAT_SEQUENCE表中增加一條記錄
INSERT INTO ``MYCAT_SEQUENCE`(`name`, `current_value`, `increment`) VALUES ('ORDER_MASTER', 1, 1);
5、修改schema.xml中邏輯表的自增長屬性autoIncrement=true
<table name="order_master" primaryKey="order_id" dataNode="orddb01,orddb02,orddb03,orddb04" rule="order_master" autoIncrement="true"/>
6、重啟mycat插入數據即可。
如果遇到以下問題:
ERROR 1003 (HY000): mycat sequnce err.java.lang.RuntimeException: can't fetch sequnce in db,sequnce :ORDER_MASTER detail:execute command denied to user 'im_mycat'@'192.168.56.%' for routine 'mycat.mycat_seq_nextval'
表示im_mycat用戶沒有權限使用函數,所以要給他有權限執行。
grant execute on *.* to im_mycat@'192.168.56.%';
flush privileges;
show grants for im_mycat@'192.168.56.%';
重啟mycat,執行插入數據。
5、 ER分片表操作
ER是什么東西?通俗來說就是一個表跟另外一個表有外鍵關聯關系或者密切關系。
主要是當sql中有join操作的時候,需要將相關數據分到同一個分片中。
1、在相應的分片節點都要加上數據表,如order_detail
2、修改schema.xml中的配置
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="shop_db" checkSQLschema="false" sqlMaxLimit="100">
<table name="region_info" primaryKey="region_id" dataNode="orddb,custdb,prodb" type="global"/>
<table name="order_cart" primaryKey="cart_id" dataNode="orddb" />
<table name="order_customer_addr" primaryKey="customer_addr_id" dataNode="orddb" />
<!--
<table name="order_detail" primaryKey="order_detail_id" dataNode="orddb" />
-->
<!-- 水平分片 -->
<table name="order_master" primaryKey="order_id" dataNode="orddb01,orddb02,orddb03,orddb04" rule="order_master" autoIncrement="true"/>
<!-- ER分片表-->
<table name="order_master" primaryKey="order_id" dataNode="orddb01,orddb02,orddb03,orddb04" rule="order_master" autoIncrement="true">
<childTable name="order_detail" primaryKey="order_detail_id" joinKey="order_id" parentKey="order_id" autoIncrement="true" />
</table>
<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" />
<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_supplier_info" primaryKey="supplier_id" dataNode="prodb" />
</schema>
<dataNode name="orddb" dataHost="mysql11" database="order_db" />
<dataNode name="custdb" dataHost="mysql12" database="customer_db" />
<dataNode name="prodb" dataHost="mysql13" database="product_db" />
<!-- 水平分片 -->
<dataNode name="orddb01" dataHost="mysql11" database="orddb01" />
<dataNode name="orddb02" dataHost="mysql11" database="orddb02" />
<dataNode name="orddb03" dataHost="mysql12" database="orddb01" />
<dataNode name="orddb04" dataHost="mysql13" database="orddb01" />
<!-- 全局自增id-->
<dataNode name="mycat" dataHost="mysql10" database="mycat" />
<dataHost name="mysql10" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.10" url="192.168.56.10:3306" user="im_mycat" password="123456" />
</dataHost>
<dataHost name="mysql11" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.11" url="192.168.56.11:3306" user="im_mycat" password="123456" />
</dataHost>
<dataHost name="mysql12" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.12" url="192.168.56.12:3306" user="im_mycat" password="123456" />
</dataHost>
<dataHost name="mysql13" maxCon="1000" minCon="10" balance="3" writeType="0" dbType="mysql" dbDriver="native" switchType="1">
<heartbeat>select user()</heartbeat>
<writeHost host="192.168.56.13" url="192.168.56.13:3306" user="im_mycat" password="123456" />
</dataHost>
</mycat:schema>
3、因為配置了order_detail的是配置自增長,所以需要參考配置全局自增id的操作即可。
4、重啟mycat即可。
其他
上一篇文章:MyCat基礎知識