原文:http://blog.csdn.net/shagoo/article/details/8191346
項目已經遷移到Git上面,位址為:https://github.com/alibaba/cobar
最近好不容易抽空研究了下Cobar,感覺這個産品确實很不錯(在文檔方面比Amoeba強多了),特此推薦給大家。Cobar是阿裡巴巴研發的關系型資料的分布式處理系統,該産品成功替代了原先基于Oracle的資料存儲方案,目前已經接管了3000+個MySQL資料庫的schema,平均每天處理近50億次的SQL執行請求。
首先,使用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的安裝和配置步驟:
1) 系統對外提供的資料庫名是dbtest,并且其中有兩張表tb1和tb2。
2) tb1表的資料被映射到實體資料庫dbtest1的tb1上。
3) tb2表的一部分資料被映射到實體資料庫dbtest2的tb2上,另外一部分資料被映射到實體資料庫dbtest3的tb2上。
1、環境準備
作業系統:Linux或者Windows (推薦在Linux環境下運作Cobar)
2、資料準備
假設本文MySQL所在伺服器IP為192.168.0.1,端口為3306,使用者名為test,密碼為空,我們需要建立schema:dbtest1、dbtest2、dbtest3,table:tb1、tb2,SQL如下:
#建立dbtest1
dropdatabaseifexistsdbtest1;
createdatabasedbtest1;
usedbtest1;
#在dbtest1上建立tb1
createtabletb1(
idintnotnull,
gmtdatetime);
#建立dbtest2
dropdatabaseifexistsdbtest2;
createdatabasedbtest2;
usedbtest2;
#在dbtest2上建立tb2
createtabletb2(
valvarchar(256));
#建立dbtest3
dropdatabaseifexistsdbtest3;
createdatabasedbtest3;
usedbtest3;
#在dbtest3上建立tb2
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)。
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEcobar:schemaSYSTEM"schema.dtd">
<cobar:schemaxmlns:cobar="http://cobar.alibaba.com/">
<!--schema定義-->
<schemaname="dbtest"dataNode="dnTest1">
<tablename="tb2"dataNode="dnTest2,dnTest3"rule="rule1"/>
</schema>
<!--資料節點定義,資料節點由資料源和其他一些參數組織而成。-->
<dataNodename="dnTest1">
<propertyname="dataSource">
<dataSourceRef>dsTest[0]</dataSourceRef>
</property>
</dataNode>
<dataNodename="dnTest2">
<dataSourceRef>dsTest[1]</dataSourceRef>
<dataNodename="dnTest3">
<dataSourceRef>dsTest[2]</dataSourceRef>
<!--資料源定義,資料源是一個具體的後端資料連接配接的表示。-->
<dataSourcename="dsTest"type="mysql">
<propertyname="location">
<location>192.168.0.1:3306/dbtest1</location><!--注意:替換為您的MySQLIP和Port-->
<location>192.168.0.1:3306/dbtest2</location><!--注意:替換為您的MySQLIP和Port-->
<location>192.168.0.1:3306/dbtest3</location><!--注意:替換為您的MySQLIP和Port-->
<propertyname="user">test</property><!--注意:替換為您的MySQL使用者名-->
<propertyname="password">test</property><!--注意:替換為您的MySQL密碼-->
<propertyname="sqlMode">STRICT_TRANS_TABLES</property>
</dataSource>
</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中找到,代碼如下:
<!DOCTYPEcobar:ruleSYSTEM"rule.dtd">
<cobar:rulexmlns:cobar="http://cobar.alibaba.com/">
<!--路由規則定義,定義什麼表,什麼字段,采用什麼路由算法。-->
<tableRulename="rule1">
<rule>
<columns>id</columns>
<algorithm><![CDATA[func1(${id})]]></algorithm>
</rule>
</tableRule>
<!--路由函數定義,應用在路由規則的算法定義中,路由函數可以自定義擴充。-->
<functionname="func1"class="com.alibaba.cobar.route.function.PartitionByLong">
<propertyname="partitionCount">2</property>
<propertyname="partitionLength">512</property>
</function>
</cobar:rule>
<!DOCTYPEcobar:serverSYSTEM"server.dtd">
<cobar:serverxmlns:cobar="http://cobar.alibaba.com/">
<!--定義Cobar使用者名,密碼-->
<username="root">
<propertyname="password">passwd</property>
<propertyname="schemas">dbtest</property>
</user>
</cobar:server>
這裡的server.xml配置比較簡單,隻配置了本地Cobar服務的資料庫結構、使用者名和密碼。在啟動Cobar服務之後,使用使用者名root和密碼passwd就可以登入Cobar服務。
4、運作Cobar
啟動Cobar服務很簡單,運用bin目錄下的start.sh即可(停止使用shutdown.sh)。啟動成功之後,可以在logs目錄下的stdout.log中看到如下日志:
10:54:19,264INFO===============================================
10:54:19,265INFOCobarisreadytostartup...
10:54:19,265INFOStartupprocessors...
10:54:19,443INFOStartupconnector...
10:54:19,446INFOInitializedataNodes...
10:54:19,470INFOdnTest1:0initsuccess
10:54:19,472INFOdnTest3:0initsuccess
10:54:19,473INFOdnTest2:0initsuccess
10:54:19,481INFOCobarManagerisstartedandlisteningon9066
10:54:19,483INFOCobarServerisstartedandlisteningon8066
10:54:19,484INFO===============================================
接着,我們就可以使用“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的心跳檢測主要用在以下兩個地方。
1、在配置資料節點的時候,我們需要使用心跳檢測來探測資料節點的運作狀況。Cobar中使用執行SQL的方式來進行探測,簡單且實用。例如,我們可以把前面執行個體中的schema.xml中的dataNode配置成下面的樣子。
......
<!--Cobar與後端資料源連接配接池大小設定-->
<propertyname="poolSize">256</property>
<!--Cobar通過心跳來實作後端資料源HA,一旦主資料源心跳失敗,便切換到備資料源上工作-->
<!--Cobar心跳是通過向後端資料源執行一條SQL語句,根據該語句的傳回結果判斷資料源的運作情況-->
<propertyname="heartbeat">selectuser()<property>
2、當我們需要對Cobar作叢集(cluster),進行負載均衡的時候,我們也需要用到心跳機制。不過此處的配置則是在server.xml中,代碼如下:
<!--組建一個Cobar叢集,隻需在cluster配置中把所有Cobar節點(注意:包括目前Cobar自身)都配置上便可-->
<cluster>
<!--node名稱,一個node表示一個Cobar節點,一旦配置了node,目前Cobar便會向此節點定期發起心跳,探測節點的運作情況-->
<nodename="cobar1">
<!--Cobar節點IP,表示目前Cobar将會向192.168.0.1上部署的Cobar發送心跳-->
<propertyname="host">192.168.0.1</property>
<!--節點的權重,用于用戶端的負載均衡,使用者可以通過指令查詢某個節點的運作情況以及權重-->
<propertyname="weight">1</property>
</node>
<!--目前Cobar将會向192.168.0.2上部署的Cobar發送心跳-->
<nodename="cobar2">
<propertyname="host">192.168.0.2</property>
<propertyname="weight">2</property>
<!--目前Cobar将會向192.168.0.3上部署的Cobar發送心跳-->
<nodename="cobar3">
<propertyname="host">192.168.0.3</property>
<propertyname="weight">3</property>
<!--使用者還可以将Cobar節點分組,以便實作schema級别的細粒度負載均衡-->
<groupname="group12">
<propertyname="nodeList">cobar1,cobar2</property>
</group>
<groupname="group23">
<propertyname="nodeList">cobar2,cobar3</property>
</cluster>
最後,簡單看一下Cobar的實作原理。
首先是系統子產品架構。
從上圖中可以看到,Cobar的前、後端子產品都實作了MySQL協定;當接受到SQL請求時,會依次進行解釋(SQL Parser)和路由(SQL Router)工作,然後使用SQL Executor去後端子產品擷取資料集(後端子產品還負責心跳檢測功能);如果資料集來自多個資料源,Cobar則需要把資料集進行組合(Result Merge),最後傳回響應。整個過程應該比較容易了解,
下面是Cobar的網絡通訊子產品架構。
從上圖中可以看出,Cobar采用了主流的Reactor設計模式來處理請求,并使用NIO進行底層的資料交換,這大大提升系統的負載能力。其中,NIOAcceptor用于處理前端請求,NIOConnector則用于管理後端的連接配接,NIOProcessor用于管理多線程事件處理,NIOReactor則用于完成底層的事件驅動機制,就是看起來和Mina和Netty的網絡模型比較相似。如果有興趣,大家還可以到Cobar站點的下載下傳頁面(http://code.alibabatech.com/wiki/display/cobar/release)擷取該項目的源碼,真是太周到了,讓我們為富有開源精神的阿裡人掌聲鼓勵一下!