這幾天研究了下Cobar, Cobar是阿里巴巴研發的關係型數據的分佈式處理系統(Amoeba的升級版,該產品成功替代了原先基於Oracle的數據存儲方案,目前已經接管了3000+個MySQL數據庫的schema,平均每天處理近50億次的SQL執行請求。)(github上面的是源碼,大家下來需要自己用maven2編譯後運行、者放Eclipse裏面運行,一開始我用maven3沒有執行成功。)
首先,使用Cobar的核心功能如下:
分佈式:
Cobar的分佈式主要是通過將表放入不同的庫來實現:
1. Cobar支持將一張表水平拆分成多份分別放入不同的庫來實現表的水平拆分
2. Cobar也支持將不同的表放入不同的庫
3. 多數情況下,用戶會將以上兩種方式混合使用
這裏需要強調的是,Cobar不支持將一張表,例如test表拆分成test_1, test_2, test_3.....放在同一個庫中,必須將拆分後的表分別放入不同的庫來實現分佈式。
HA:
在用戶配置了MySQL心跳的情況下,Cobar可以自動向後端連接的MySQL發送心跳,判斷MySQL運行狀況,一旦運行出現異常,Cobar可以自動切換到備機工作。但需要強調的是:
1. Cobar的主備切換有兩種觸發方式,一種是用戶手動觸發,一種是Cobar的心跳語句檢測到異常後自動觸發。那麼,當心跳檢測到主機異常,切換到備機,如果主機恢復了,需要用戶手動切回主機工作,Cobar不會在主機恢復時自動切換回主機,除非備機的心跳也返回異常。
2. Cobar只檢查MySQL主備異常,不關心主備之間的數據同步,因此用戶需要在使用Cobar之前在MySQL主備上配置雙向同步,詳情可以參閱MySQL參考手冊。
其次,我們也需要注意Cobar的功能約束:
1) 不支持跨庫情況下的join、分頁、排序、子查詢操作。
2) SET語句執行會被忽略,事務和字符集設置除外。
3) 分庫情況下,insert語句必須包含拆分字段列名。
4) 分庫情況下,update語句不能更新拆分字段的值。
5) 不支持SAVEPOINT操作。
6) 暫時只支持MySQL數據節點。
7) 使用JDBC時,不支持rewriteBatchedStatements=true參數設置(默認爲false)。
8) 使用JDBC時,不支持useServerPrepStmts=true參數設置(默認爲false)。
9) 使用JDBC時,BLOB, BINARY, VARBINARY字段不能使用setBlob()或setBinaryStream()方法設置參數。
然後,我們來分析一下Cobar邏輯層次圖:
* dataSource:數據源,表示一個具體的數據庫連接,與物理存在的數據庫schema一一對應。
* dataNode:數據節點,由主、備數據源,數據源的HA以及連接池共同組成,可以將一個dataNode理解爲一個分庫。
* table:表,包括拆分表(如tb1,tb2)和非拆分表。
* tableRule:路由規則,用於判斷SQL語句被路由到具體哪些datanode執行。
* schema:cobar可以定義包含拆分表的schema(如schema1),也可以定義無拆分表的schema(如schema2)。
Cobar支持的數據庫結構(schema)的層次關係具有較強的靈活性,用戶可以將表自由放置不同的datanode,也可將不同的datasource放置在同一MySQL實例上。在實際應用中,我們需要通過配置文件(schema.xml)來定義我們需要的數據庫服務器和表的分佈策略,這點我們將在後面的安裝和配置部分中介紹到。
接着,我們來介紹Cobar的安裝和配置步驟:
下面我們將使用一個最簡單的分庫分表的例子來說明Cobar的基本用法,數據庫schema如下圖(該實例也可參考:Cobar產品首頁)。
1) 系統對外提供的數據庫名是dbtest,並且其中有兩張表tb1和tb2。
2) tb1表的數據被映射到物理數據庫dbtest1的tb1上。
3) tb2表的一部分數據被映射到物理數據庫dbtest2的tb2上,另外一部分數據被映射到物理數據庫dbtest3的tb2上。
1、環境準備
操作系統:Linux或者Windows (推薦在Linux環境下運行Cobar)
MySQL:http://www.mysql.com/downloads/ (推薦使用5.1以上版本)
JDK:http://www.oracle.com/technetwork/java/javase/downloads/ (推薦使用1.6以上版本)
Cobar:https://github.com/alibaba/cobar (下載tar.gz或者zip文件,特意說明下,阿里的開源全部移到github上去了,裏面有很多阿里人的作品,當然包含著名的dubbo,地址是:https://github.com/alibaba/)
2、數據準備
假設本文MySQL所在服務器IP爲192.168.0.1,端口爲3306,用戶名爲test,密碼爲空,我們需要創建schema:dbtest1、dbtest2、dbtest3,table:tb1、tb2,SQL如下:
[sql] view plaincopy
1. #創建dbtest1
2. drop database if exists dbtest1;
3. create database dbtest1;
4. use dbtest1;
5. #在dbtest1上創建tb1
6. create table tb1(
7. id int not null,
8. gmt datetime);
9.
10.#創建dbtest2
11.drop database if exists dbtest2;
12.create database dbtest2;
13.use dbtest2;
14.#在dbtest2上創建tb2
15.create table tb2(
16.id int not null,
17.val varchar(256));
18.
19.#創建dbtest3
20.drop database if exists dbtest3;
21.create database dbtest3;
22.use dbtest3;
23.#在dbtest3上創建tb2
24.create table tb2(
25.id int not null,
26.val varchar(256));
3、配置Cobar
Cobar解壓之後有四個目錄:
bin/:可執行文件目錄,包含啓動(start)、關閉(shutdown)和重啓(restart)腳本
lib/:邏輯類庫目錄,包含了Cobar所需的jar包
conf/:配置文件目錄,下面會詳細介紹
logs/:運行日誌目錄,最主要的log有兩個:程序日誌(stdout.log)和控制檯輸出(console.log)
配置文件的用法如下:
log4j.xml:日誌配置,一般來說保持默認即可
schema.xml:定義了schema邏輯層次圖中的所有元素,並利用這些元素以及rule.xml中定義的規則組建分佈式數據庫系統
rule.xml:定義了分庫分表的規則
server.xml:系統配置文件
我們在schema.xml中配置數據庫結構(schema)、數據節點(dataNode)、以及數據源(dataSource)。
[html] view plaincopy
1. <?xml version="1.0" encoding="UTF-8"?>
2. <!DOCTYPE cobar:schema SYSTEM "schema.dtd">
3. <cobar:schema xmlns:cobar="http://cobar.alibaba.com/">
4.
5. <!-- schema定義 -->
6. <schema name="dbtest" dataNode="dnTest1">
7. <table name="tb2" dataNode="dnTest2,dnTest3" rule="rule1" />
8. </schema>
9.
10. <!-- 數據節點定義,數據節點由數據源和其他一些參數組織而成。-->
11. <dataNode name="dnTest1">
12. <property name="dataSource">
13. <dataSourceRef>dsTest[0]</dataSourceRef>
14. </property>
15. </dataNode>
16. <dataNode name="dnTest2">
17. <property name="dataSource">
18. <dataSourceRef>dsTest[1]</dataSourceRef>
19. </property>
20. </dataNode>
21. <dataNode name="dnTest3">
22. <property name="dataSource">
23. <dataSourceRef>dsTest[2]</dataSourceRef>
24. </property>
25. </dataNode>
26.
27. <!-- 數據源定義,數據源是一個具體的後端數據連接的表示。-->
28. <dataSource name="dsTest" type="mysql">
29. <property name="location">
30. <location>192.168.0.1:3306/dbtest1</location> <!--注意:替換爲您的MySQL IP和Port-->
31. <location>192.168.0.1:3306/dbtest2</location> <!--注意:替換爲您的MySQL IP和Port-->
32. <location>192.168.0.1:3306/dbtest3</location> <!--注意:替換爲您的MySQL IP和Port-->
33. </property>
34. <property name="user">test</property> <!--注意:替換爲您的MySQL用戶名-->
35. <property name="password">test</property> <!--注意:替換爲您的MySQL密碼-->
36. <property name="sqlMode">STRICT_TRANS_TABLES</property>
37. </dataSource>
38.</cobar:schema>
我們注意到,上述配置實際上已經把圖2中的數據庫結構配置好了。dbtest主要映射的是dnTest1庫(即192.168.0.1:3306/dbtest1庫),而其中的tb2表則是按照規則rule1,被分配到dnTest2庫(即192.168.0.1:3306/dbtest2庫)和dnTest3庫(即192.168.0.1:3306/dbtest3庫)中。此外,規則rule1的定義可以在rule.xml中找到,代碼如下:
[html] view plaincopy
1. <?xml version="1.0" encoding="UTF-8"?>
2. <!DOCTYPE cobar:rule SYSTEM "rule.dtd">
3. <cobar:rule xmlns:cobar="http://cobar.alibaba.com/">
4.
5. <!-- 路由規則定義,定義什麼表,什麼字段,採用什麼路由算法。-->
6. <tableRule name="rule1">
7. <rule>
8. <columns>id</columns>
9. <algorithm><![CDATA[ func1(${id})]]></algorithm>
10. </rule>
11. </tableRule>
12.
13. <!-- 路由函數定義,應用在路由規則的算法定義中,路由函數可以自定義擴展。-->
14. <function name="func1" class="com.alibaba.cobar.route.function.PartitionByLong">
15. <property name="partitionCount">2</property>
16. <property name="partitionLength">512</property>
17. </function>
18.</cobar:rule>
結合schema.xml中的內容,我們可以看出分表的規則是,按照id字段把tb2表中的數據分配到dnTest2和dnTest3兩個分區中,其中id小於512的數據會被放到dnTest2庫的分區中,而其餘的會被放到dnTest3庫的分區中,更多路由算法可以參考《路由文檔》。最後,我們來看一下server.xml的配置,代碼如下。
[html] view plaincopy
1. <?xml version="1.0" encoding="UTF-8"?>
2. <!DOCTYPE cobar:server SYSTEM "server.dtd">
3. <cobar:server xmlns:cobar="http://cobar.alibaba.com/">
4.
5. <!--定義Cobar用戶名,密碼-->
6. <user name="root">
7. <property name="password">passwd</property>
8. <property name="schemas">dbtest</property>
9. </user>
10.</cobar:server>
這裏的server.xml配置比較簡單,只配置了本地Cobar服務的數據庫結構、用戶名和密碼。在啓動Cobar服務之後,使用用戶名root和密碼passwd就可以登錄Cobar服務。
4、運行Cobar
啓動Cobar服務很簡單,運用bin目錄下的start.sh即可(停止使用shutdown.sh)。啓動成功之後,可以在logs目錄下的stdout.log中看到如下日誌:
[html] view plaincopy
1. 10:54:19,264 INFO ===============================================
2. 10:54:19,265 INFO Cobar is ready to startup ...
3. 10:54:19,265 INFO Startup processors ...
4. 10:54:19,443 INFO Startup connector ...
5. 10:54:19,446 INFO Initialize dataNodes ...
6. 10:54:19,470 INFO dnTest1:0 init success
7. 10:54:19,472 INFO dnTest3:0 init success
8. 10:54:19,473 INFO dnTest2:0 init success
9. 10:54:19,481 INFO CobarManager is started and listening on 9066
10.10:54:19,483 INFO CobarServer is started and listening on 8066
11.10:54:19,484 INFO ===============================================
接着,我們就可以使用“mysql -h127.0.0.1 -uroot -ppasswd -P8066 -Ddbtest”命令來登錄Cobar服務了,再接下來的操作就和在其他MySQL Client中一樣了。比如,我們可以使用“show databases”命令查看數據庫,使用“show tables”命令查看數據表,如下圖:
接着,我們按照下圖中的SQL指定向數據表插入測試記錄。
可以看到,這裏的tb2中包含了id爲1、2、513的3條記錄。而實際上,這3條記錄存儲在不同的物理數據庫上的,大家可以到物理庫上驗證一下。
至於Cobar的連接和使用方法和MySQL一樣,Java程序中可以使用JDBC(建議5.1以上的版本),PHP中可以使用PDO。當然,Cobar還提供HA、集羣等高級的功能,更多信息請參考其《產品文檔》。此外,產品文檔中還爲我們提供了詳細的PPT文檔《Cobar原理及應用.ppt》來介紹Cobar在實際生產環境中的使用方法。
此外,特別解釋一下大家可能比較關心的心跳檢測問題,Cobar的心跳檢測主要用在以下兩個地方。
1、在配置數據節點的時候,我們需要使用心跳檢測來探測數據節點的運行狀況。Cobar中使用執行SQL的方式來進行探測,簡單且實用。例如,我們可以把前面實例中的schema.xml中的dataNode配置成下面的樣子。
[html] view plaincopy
1. ... ...
2. <!-- 數據節點定義,數據節點由數據源和其他一些參數組織而成。-->
3. <dataNode name="dnTest1">
4. <property name="dataSource">
5. <dataSourceRef>dsTest[0]</dataSourceRef>
6. </property>
7. <!--Cobar與後端數據源連接池大小設置-->
8. <property name="poolSize">256</property>
9. <!--Cobar通過心跳來實現後端數據源HA,一旦主數據源心跳失敗,便切換到備數據源上工作-->
10. <!--Cobar心跳是通過向後端數據源執行一條SQL語句,根據該語句的返回結果判斷數據源的運行情況-->
11. <property name="heartbeat">select user()<property>
12. </dataNode>
13.... ...
2、當我們需要對Cobar作集羣(cluster),進行負載均衡的時候,我們也需要用到心跳機制。不過此處的配置則是在server.xml中,代碼如下:
[html] view plaincopy
1. ... ...
2. <!--組建一個Cobar集羣,只需在cluster配置中把所有Cobar節點(注意:包括當前Cobar自身)都配置上便可-->
3. <cluster>
4. <!--node名稱,一個node表示一個Cobar節點,一旦配置了node,當前Cobar便會向此節點定期發起心跳,探測節點的運行情況-->
5. <node name="cobar1">
6. <!--Cobar節點IP, 表示當前Cobar將會向192.168.0.1上部署的Cobar發送心跳-->
7. <property name="host">192.168.0.1</property>
8. <!--節點的權重,用於客戶端的負載均衡,用戶可以通過命令查詢某個節點的運行情況以及權重-->
9. <property name="weight">1</property>
10. </node>
11. <!--當前Cobar將會向192.168.0.2上部署的Cobar發送心跳-->
12. <node name="cobar2">
13. <property name="host">192.168.0.2</property>
14. <property name="weight">2</property>
15. </node>
16. <!--當前Cobar將會向192.168.0.3上部署的Cobar發送心跳-->
17. <node name="cobar3">
18. <property name="host">192.168.0.3</property>
19. <property name="weight">3</property>
20. </node>
21. <!--用戶還可以將Cobar節點分組,以便實現schema級別的細粒度負載均衡-->
22. <group name="group12">
23. <property name="nodeList">cobar1,cobar2</property>
24. </group>
25. <group name="group23">
26. <property name="nodeList">cobar2,cobar3</property>
27. </group>
28. </cluster>
29.... ...
最後,簡單看一下Cobar的實現原理。
首先是系統模塊架構。
從上圖中可以看到,Cobar的前、後端模塊都實現了MySQL協議;當接受到SQL請求時,會依次進行解釋(SQL Parser)和路由(SQL Router)工作,然後使用SQL Executor去後端模塊獲取數據集(後端模塊還負責心跳檢測功能);如果數據集來自多個數據源,Cobar則需要把數據集進行組合(Result Merge),最後返回響應。整個過程應該比較容易理解,
下面是Cobar的網絡通訊模塊架構。
從上圖中可以看出,Cobar採用了主流的Reactor設計模式來處理請求,並使用NIO進行底層的數據交換,這大大提升系統的負載能力。其中,NIOAcceptor用於處理前端請求,NIOConnector則用於管理後端的連接,NIOProcessor用於管理多線程事件處理,NIOReactor則用於完成底層的事件驅動機制,就是看起來和Mina和Netty的網絡模型比較相似。如果有興趣,大家還可以到Cobar站點的下載頁面(https://github.com/alibaba/cobar)獲取該項目的源碼,感謝阿里人的付出!
最後說點題外話,目前國內關於mysql分佈式中間有
360公司的Atlas:http://www.guokr.com/blog/475765/
淘寶的tddl:http://www.guokr.com/blog/475765/
京東的藍海豚:http://cio.zdnet.com.cn/cio/2014/0731/3028990.shtml?fromrss=rss
但是還是阿里的cobar好些,因爲他開源了,除了中間件本身,還開源提供驅動、管理器。