一、mycat讀寫分離
Mycat的讀寫分離是建立在Mysq的主從複製的基礎上的
#修改配置文件 schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<dataNode name="dn1" dataHost="host1" database="test1" />
<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="192.168.171.135:3306" user="root"
password="123">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="192.168.171.146:3306" user="root" password="123" />
</writeHost>
</dataHost>
</mycat:schema>
設置有兩種,如下:
(1) 設置balance="1"與writeType=“0”
Balance參數設置:
修改的balance屬性,通過此屬性配置讀寫分離的類型 負載均衡類型,目前的取值有4 種:
(1) balance=“0”, 不開啓讀寫分離機制, 所有讀操作都發送到當前可用的 writeHost 上。
(2) balance=“1”,全部的 readHost 與 stand by writeHost 參與 select 語句的負載均衡,簡單的說,當雙主雙從 模式(M1->S1, M2->S2,並且 M1 與 M2 互爲主備),正常情況下, M2,S1,S2 都參與 select 語句的負載均衡。
(3) balance=“2”,所有讀操 作都隨機的在 writeHost、 readhost 上分發。
(4) balance=“3”,所有讀請求隨機的分發到 readhost 執行, writerHost 不負擔讀壓力
WriteType參數設置:
writeType=“0”, 所有寫操作都發送到可用的writeHost上。
writeType=“1”,所有寫操作都隨機的發送到readHost。
writeType=“2”,所有寫操作都隨機的在writeHost、readhost分上發。
“readHost是從屬於writeHost的,即意味着它從那個writeHost獲取同步數據,因此,當它所屬的writeHost宕機 了,則它也不會再參與到讀寫分離中來,即“不工作了”,這是因爲此時,它的數據已經“不可靠”了。基於這個考 慮,目前mycat 1.3和1.4版本中,若想支持MySQL一主一從的標準配置,並且在主節點宕機的情況下,從節點 還能讀取數據,則需要在Mycat裏配置爲兩個writeHost並設置banlance=1。”
(2) 設置switchType=“2” 與slaveThreshold=“100”
switchType 目前有三種選擇:
-1:表示不自動切換
1 :默認值,自動切換
2 :基於MySQL主從同步的狀態決定是否切換
“Mycat心跳檢查語句配置爲 show slave status ,dataHost 上定義兩個新屬性: switchType=“2” 與 slaveThreshold=“100”,此時意味着開啓MySQL主從複製狀態綁定的讀寫分離與切換機制。Mycat心跳機制通過 檢測 show slave status 中的 “Seconds_Behind_Master”, “Slave_IO_Running”, “Slave_SQL_Running” 三個字段來 確定當前主從同步的狀態以及Seconds_Behind_Master主從複製時延。“
二、垂直拆分–分庫
一個數據庫由很多表的構成,每個表對應着不同的業務,垂直切分是指按照業務將表進行分類, 分佈到不同 的 數據庫上面,這樣也就將數據或者說壓力分擔到不同的庫上面, 如何劃分表 分庫的原則: 有緊密關聯關係的 表應該在一個庫裏,相互沒有關聯關係的表可以分到不同的庫裏。
#修改 schema 配置文件
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<table name="customer" dataNode="dn2"></table>
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<dataNode name="dn1" dataHost="host1" database="test1" />
<dataNode name="dn2" dataHost="host2" database="test1" />
<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="192.168.171.135:3306" user="root"
password="123">
<!-- can have multi read hosts -->
<readHost host="hostS2" url="192.168.171.146:3306" user="root" password="123" />
</writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM2" url="192.168.171.131:3306" user="root" password="123">
</writeHost>
</dataHost>
</mycat:schema>
#登錄到數據庫,創建表
[root@mycatconf]#mysql -umycat -p123456 -h192.168.171.134 -P8066
mysql>CREATE TABLE customer( id INT AUTO_INCREMENT, NAME VARCHAR(200), PRIMARY KEY(id) );
mysql>CREATE TABLE orders( id INT AUTO_INCREMENT, order_type INT, customer_id INT, amount DECIMAL(10,2), PRIMARY KEY(id) );
mysql>CREATE TABLE orders_detail( id INT AUTO_INCREMENT, detail VARCHAR(2000), order_id INT, PRIMARY KEY(id) );
mysql>CREATE TABLE dict_order_type( id INT AUTO_INCREMENT, order_type VARCHAR(200), PRIMARY KEY(id) );
#以上四個表如何分庫?客戶表分在一個數據庫,另外三張都需要關聯查詢,分在另外一個數據庫。
mysql> show tables;
+----+--------------+
|Tables_in_xxq |
+----+--------------+
| dict_order_type|
| orders |
| orders_detail |
| tab1 |
+----+---------------+
mysql>show tables;
+----+--------------+
| customer |
+----+---------------+
三、水平拆分–分表
相對於垂直拆分,水平拆分不是將表做分類,而是按照某個字段的某種規則來分散到多個庫之中, 每個表中 包 含一部分數據。簡單來說,我們可以將數據的水平切分理解爲是按照數據行的切分,就 是將表中的某些行切分 到一個數據庫,而另外的某些行又切分到其他的數據庫中. 實現分表 選擇要拆分的表 MySQL 單表存儲數據條數是有瓶頸的,單表達到 1000 萬條數據就達到了瓶頸,會 影響查詢效率, 需要進行水平拆分(分表) 進行優化。 例如:例子中的 orders、 orders_detail 都已經達到 600 萬行數據,需要進行分表優化。 分表字段 以 orders 表爲例,可以根據不同自字段進行分表
#修改配置文件 schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
<table name="customer" dataNode="dn2"></table>
<table name="orders" dataNode="dn1,dn2" rule="mod_rule"> # 爲 orders 表設置數據節點爲 dn1、 dn2, 並指定分片規則爲 mod_rule(自定義的名字)
<childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
</table>
</schema>
<dataNode name="dn1" dataHost="host1" database="test1" />
<dataNode name="dn2" dataHost="host2" database="test1" />
<dataHost name="host1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.171.135:3306" user="root" password="123">
<readHost host="hostS1" url="192.168.171.145:3306" user="root" password="123" />
</writeHost>
</dataHost>
<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.171.132:3306" user="root" password="123">
</writeHost>
</dataHost>
</mycat:schema>
#修改配置文件 rule.xml
#在 rule 配置文件裏新增分片規則 mod_rule,並指定規則適用字段爲 customer_id,
#還有選擇分片算法 mod-long(對字段求模運算) , customer_id 對兩個節點求模,根據結果分 片
#配置算法 mod-long 參數 count 爲 2,兩個節點
<tableRule name="mod_rule">
<rule>
<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">2</property>
</function>
在數據節點 dn2 上建 orders 表
mysql>CREATE TABLE orders_detail( id INT AUTO_INCREMENT, detail VARCHAR(2000), order_id INT, PRIMARY KEY(id) );
重啓 Mycat,讓配置生效
mysql> insert into orders_detail(id,detail,order_id) values (1,'detail',1);
mysql> insert into orders_detail(id,detail,order_id) values (2,'detail',2);
mysql> insert into orders_detail(id,detail,order_id) values (3,'detail',3);
mysql> insert into orders_detail(id,detail,order_id) values (4,'detail',4); )
mysql> insert into orders_detail(id,detail,order_id) values (5,'detail',5);
mysql> insert into orders_detail(id,detail,order_id) values (6,'detail',6);
訪問 Mycat 實現分片
mysql> select o.*,od.detail from orders as o inner join orders_detail as od on o.id=od.order_id;
+----+------------+-------------+-----------+--------+
| id | order_type | customer_id | amount | detail |
+----+------------+-------------+-----------+--------+
| 1 | 101 | 100 | 100100.00 | detail |
| 2 | 101 | 100 | 100300.00 | detail |
| 6 | 102 | 100 | 100020.00 | detail |
| 3 | 101 | 101 | 120000.00 | detail |
| 4 | 101 | 101 | 103000.00 | detail |
| 5 | 102 | 101 | 100400.00 | detail |
+----+------------+-------------+-----------+--------+
四、全局表
在分片的情況下,當業務表因爲規模而進行分片以後,業務表與這些附屬的字典表之間的關聯, 就 成了比較 棘手的問題,考慮到字典表具有以下幾個特性:
① 變動不頻繁
② 數據量總體變化不大
③ 數據規模不 大,很少有超過數十萬條記錄
Mycat 定義了一種特殊的表,稱之爲“全局表”,全局表具有以下特性:
① 全局表的插入、更新操作會實時在所有節點上執行,保持各個分片的數據一致性
② 全局表的查詢操作,只從 一個節點獲取
③ 全局表可以跟任何一個表進行 JOIN 操作 將字典表或者符合字典表特性的一些表定義爲全局 表,則從另外一個方面,很好的解決了數據 JOIN 的難題。 通過全局表+基於 E-R 關係的分片策略, Mycat 可 以滿足 80%以上的企業應用開發
#修改 schema.xml 配置文件
<table name="customer" dataNode="dn2"></table>
<table name="orders" dataNode="dn1,dn2" rule="mod_rule" >
<childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
</table>
<table name="dict_order_type" dataNode="dn1,dn2" type="global">
</table>
#在dn2 創建 dict_order_type 表
mysql>CREATE TABLE dict_order_type( id INT AUTO_INCREMENT, order_type VARCHAR(200), PRIMARY KEY(id) );
#重啓 Mycat
#訪問 Mycat 向 dict_order_type 表插入數據
mysql> insert into dict_order_type (id,order_type) values (101,'type1');
mysql> insert into dict_order_type (id,order_type) values (102,'type2');
mysql> select * from dict_order_type ;
+-----+------------+
| id | order_type |
+-----+------------+
| 101 | type1 |
| 102 | type2 |
+-----+------------+
2 rows in set (0.05 sec)
常用分片規則
1、 取模 此規則爲對分片字段求摸運算。 也是水平分表最常用規則。 5.1 配置分表中, orders 表採用了此規 則。
2、 分片枚舉 通過在配置文件中配置可能的枚舉 id,自己配置分片,本規則適用於特定的場景,比如有些 業務 需要按照省份或區縣來做保存,而全國省份區縣固定的,這類業務使用本條規則。