文章共 1796字,閱讀大約需要 4分鐘 !
概 述
在如今海量資料充斥的網際網路環境下,分庫分表的意義我想在此處就不用贅述了。而分庫分表目前流行的方案最起碼有兩種:
- 方案一:基於應用層的分片,即應用層程式碼直接完成分片邏輯
- 方案二:基於代理層的分片,即在應用程式碼和底層資料庫中間新增一層代理層,而分片的路由規則則由代理層來進行處理
而本文即將要實驗的 MyCAT框架就屬於第二種方案的代表作品。
注: 本文首發於 My Personal Blog:CodeSheep·程式羊,歡迎光臨 小站
環境規劃
在本文中,我拿出了三臺 Linux主機投入試驗,各節點的角色分配如下表所示:
節點 | 部署元件 | 角色 |
---|---|---|
192.168.199.75 | MySQL 、 MyCAT | master |
192.168.199.74 | MySQL | slave |
192.168.199.76 | MySQL | standby master |
如果說上面這張表不足以說明實驗模型,那接下來再給一張圖好了,如下所示:
我想這樣看來的話,各個節點布了哪些元件,節點間的角色關係應該一目瞭然了吧
實驗環境規劃好了以後,接下來進行具體的部署與實驗過程,首先當然是 MyCAT代理的部署
MyCAT 部署
關於該部分,網上教程實在太多了,但最好還是參考官方文件來吧,下面也簡述一下部署過程
- 下載 MyCAT並解壓安裝
這裡安裝的是 MyCAT 1.5
wget https://raw.githubusercontent.com/MyCATApache/Mycat-download/master/1.5-RELEASE/Mycat-server-1.5.1-RELEASE-20161130213509-linux.tar.gz
tar -zxvf Mycat-server-1.5.1-RELEASE-20161130213509-linux.tar.gz
mv mycat /usr/local/
複製程式碼
- 啟動 MyCAT
./mycat start
複製程式碼
- MyCAT連線測試
mysql -utest -ptest -h127.0.0.1 -P8066 -DTESTDB
複製程式碼
MyCAT 配置
官網上對於這一部分的描述是非常詳細的,MyCAT 配置主要涉及三個 XML配置檔案:
server.xml
:MyCAT框架的系統引數/使用者引數配置檔案schema.xml
: MyCAT框架的邏輯庫表與分片的配置檔案rule.xml
:MyCAT框架的邏輯庫表分片規則的配置檔案
用如下圖形可以形象地表示出這三個 XML配置檔案的配置內容和相互關係:
下面來進入具體的實驗環節 ,這也是圍繞 MyCAT提供的幾大主要功能展開的,主要涉及三個方面
- 分庫分表
- 讀寫分離
- 主備切換
實驗之前,我們先給出公共的 server.xml
檔案的配置,這部分後續實驗過程中並不修改,其也就是定義了系統引數和使用者引數:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://org.opencloudb/">
<system>
<property name="defaultSqlParser">druidparser</property>
<!-- <property /> 這塊諸多的property配置在此就不配置了,參照官網按需配置 -->
</system>
<user name="test">
<property name="password">test</property>
<property name="schemas">TESTDB</property>
</user>
<user name="user">
<property name="password">user</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
複製程式碼
分庫分表實驗
預期實驗效果:通過 MyCAT代理往一張邏輯表中插入的多條資料,在後端自動地分配在不同的物理資料庫表上
我們按照本文 **第二節【環境規劃】**中給出的實驗模型圖來給出如下的 MyCAT邏輯庫配置檔案 schema.xml
和 分庫分表規則配置檔案 rule.xml
- 準備配置檔案
schema.xml
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://org.opencloudb/" >
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="travelrecord" dataNode="dn1,dn2" rule="sharding-by-month" />
</schema>
<dataNode name="dn1" dataHost="testhost" database="db1" />
<dataNode name="dn2" dataHost="testhost" database="db2" />
<dataHost name="testhost" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="-1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="localhost:3306" user="root" password="xxxxxx">
<readHost host="hostS1" url="192.168.199.74:3306" user="root" password="xxxxxx" />
</writeHost>
<writeHost host="hostM2" url="192.168.199.76:3306" user="root" password="xxxxxx">
</writeHost>
</dataHost>
</mycat:schema>
複製程式碼
其中定義了實驗用到的 hostM1、hostS1 和 hostM2
rule.xml
<tableRule name="sharding-by-month">
<rule>
<columns>create_date</columns>
<algorithm>partbymonth</algorithm>
</rule>
</tableRule>
<function name="partbymonth"
class="org.opencloudb.route.function.PartitionByMonth">
<property name="dateFormat">yyyy-MM-dd</property>
<property name="sBeginDate">2018-11-01</property>
</function>
複製程式碼
這裡配置了
sharding-by-month
的分庫分表規則,即按照表中的create_date
欄位進行分割,從2018-11-01
日期開始,月份不同的資料落到不同的物理資料庫表中
- 在三個物理節點資料庫上分別建立兩個庫 db1和 db2
create database db1;
create database db2;
複製程式碼
- 連線 MyCAT
mysql -utest -ptest -h127.0.0.1 -P8066 -DTESTDB
複製程式碼
- 通過 MyCAT來建立資料庫
travelrecord
create table travelrecord (id bigint not null primary key,city varchar(100),create_date DATE);
複製程式碼
- 通過 MyCAT來往
travelrecord
表中插入兩條資料
insert into travelrecord(id,city,create_date) values(1,'NanJing','2018-11-3');
insert into travelrecord(id,city,create_date) values(2,'BeiJing','2018-12-3');
複製程式碼
由於插入的這兩條記錄的 create_date
分別是 2018-11-3
和 2018-12-3
,而我們配的分庫分表的規則即是根據 2018-11-01
這個日期為起始來進行遞增的,按照前面我們配的分片規則,理論上這兩條記錄按照 create_date
日期欄位的不同,應該分別插入到 hostM1的 db1和 db2兩個不同的資料庫中。
- 驗證一下資料分片的效果
由於 hostM1和 hostS1組成了 主-從庫 關係,因此剛插入的兩條資料也應該相應自動同步到 hostS1的 db1和 db2兩個資料庫中,不妨也來驗證一下:
讀寫分離實驗
**預期實驗效果:**開啟了 MyCAT的讀寫分離機制後,讀寫資料操作各行其道,互不干擾
此節實驗用到的配置檔案 schema.xml
和 rule.xml
基本和上面的【分庫分表】實驗沒什麼不同,只是我們需要關注一下 schema.xml
配置檔案中 <dataHost />
標籤裡的 balance
欄位,它是與讀寫分離息息相關的配置:
因此我們就需要弄清楚 標籤中 balance引數的含義:
balance="0"
:不開啟讀寫分離機制,即讀請求僅分發到 writeHost上balance="1"
:讀請求隨機分發到當前 writeHost對應的 readHost和 standby writeHost上balance="2"
:讀請求隨機分發到當前 dataHost內所有的 writeHost / readHost上balance="3"
:讀請求隨機分發到當前 writeHost對應的 readHost上
我們驗證一下 balance="1"
的情況,即開啟讀寫分離機制,且讀請求隨機分發到當前 writeHost對應的 readHost和 standby writeHost上,而對於本文來講,也即:hostS1 和 hostM2 上
我們來做兩次資料表的 SELECT
讀操作:
mysql> select * from travelrecord limit 6;
+----+----------+-------------+
| id | city | create_date |
+----+----------+-------------+
| 3 | TianJing | 2018-11-04 |
| 5 | ShenYang | 2018-11-05 |
| 4 | Wuhan | 2018-12-04 |
| 6 | Harbin | 2018-12-05 |
+----+----------+-------------+
4 rows in set (0.08 sec)
mysql> select * from travelrecord limit 6;
+----+---------+-------------+
| id | city | create_date |
+----+---------+-------------+
| 2 | BeiJing | 2018-12-03 |
| 8 | WuXi | 2018-12-06 |
| 1 | NanJing | 2018-11-03 |
| 7 | SuZhou | 2018-11-06 |
+----+---------+-------------+
4 rows in set (0.01 sec)
複製程式碼
然後我們取出 mycat.log
日誌檢視一下具體詳情,我們發現第一次 select
讀操作分發到了 hostM2
上:
而第二次 select
讀操作分發到了 hostS1
上:
主備切換實驗
**預期實驗效果:**開啟 MyCAT的主備機制後,當主庫當機時,自動切換到備用機進行操作
關於主備切換,則需要弄清楚 <dataHost />
標籤中 switchType
引數的含義:
switchType="-1"
:不自動切換主備資料庫switchType="1"
:自動切換主備資料庫switchType="2"
:基於MySQL主從複製的狀態來決定是否切換,需修改heartbeat語句:show slave status
switchType="3"
:基於Galera(叢集多節點複製)的切換機制,需修改heartbeat語句:show status like 'wsrep%'
此處驗證一下 Mycat的主備自動切換效果。為此首先我們將 switchType="-1"
設定為 switchType="1"
,並重啟 MyCat服務:
<dataHost name="testhost" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
複製程式碼
在本實驗環境中,在 hostM1 和 hostM2均正常時,預設寫資料時是寫到 hostM1的
- 接下來手動停止 hostM1 上的 MySQL資料庫來模擬 hostM1 當機:
systemctl stop mysqld.service
複製程式碼
接下來再通過 MyCat插入如下兩條資料:
insert into travelrecord(id,city,create_date) values(3,'TianJing','2018-11-4');
insert into travelrecord(id,city,create_date) values(4,'Wuhan','2018-12-4');
複製程式碼
效果如下:
- 此時,我們恢復 hostM1,但接下來的資料寫入依然進入 hostM2
insert into travelrecord(id,city,create_date) values(5,'ShenYang','2018-11-5');
insert into travelrecord(id,city,create_date) values(6,'Harbin','2018-12-5');
複製程式碼
- 接下來手動讓 hostM2當機,看 hostM1 是否能升級為主寫節點
再插入兩條資料:
insert into travelrecord(id,city,create_date) values(7,'SuZhou','2018-11-6');
insert into travelrecord(id,city,create_date) values(8,'WuXi','2018-12-6');
複製程式碼
很明顯,答案是肯定的
後 記
由於能力有限,若有錯誤或者不當之處,還請大家批評指正,一起學習交流!
- My Personal Blog:CodeSheep 程式羊
- 我的半年技術部落格之路
可 長按 或 掃描 下面的 小心心 來訂閱作者公眾號 CodeSheep,獲取更多 務實、能看懂、可復現的 原創文 ↓↓↓