http://blog.csdn.net/u013235478/article/details/53178657前端
Mycat中的路由結果是經過分片字段和分片方法來肯定的。例以下圖中的一個Mycat分庫方案:mysql
若是查詢條件中有 id 字段的狀況還好,查詢將會落到某個具體的分片。例如:sql
MySQL>select * from tt_waybill where id = 12330;數據庫
此時Mycat會計算路由結果後端
12330 % 3 = 0 –> DB1markdown
並將該請求路由到DB1上去執行。
若是查詢條件中沒有 分片字段 條件,例如:分佈式
mysql>select * from tt_waybill where waybill_no =88661;post
此時Mycat沒法計算路由,便發送到全部節點上執行:.net
DB1 –> select * from tt_waybill where waybill_no =88661;
DB2 –> select * from tt_waybill where waybill_no =88661;
DB3 –> select * from tt_waybill where waybill_no =88661;設計
若是該分片字段選擇度高,也是業務經常使用的查詢維度,通常只有一個或極少數個DB節點命中(返回結果集)。示例中只有3個DB節點,而實際應用中的DB節點數遠超過這個,假若有50個,那麼前端的一個查詢,落到MySQL數據庫上則變成50個查詢,會極大消耗Mycat和MySQL數據庫資源。
若是設計使用Mycat時有非分片字段查詢,請考慮放棄!
先看一下Mycat是如何處理分頁操做的,假若有以下Mycat分庫方案:
一張表有30份數據分佈在3個分片DB上,具體數據分佈以下
DB1:[0,1,2,3,4,10,11,12,13,14]
DB2:[5,6,7,8,9,16,17,18,19]
DB3:[20,21,22,23,24,25,26,27,28,29]
(這個示例的場景中沒有查詢條件,因此都是全分片查詢,也就沒有假定該表的分片字段和分片方法)
當應用執行以下分頁查詢時
mysql>select * from table limit 2;
Mycat將該SQL請求分發到各個DB節點去執行,並接收各個DB節點的返回結果
DB1: [0,1]
DB2: [5,6]
DB3: [20,21]
但Mycat嚮應用返回的結果集取決於哪一個DB節點最早返回結果給Mycat。若是Mycat最早收到DB1節點的結果集,那麼Mycat返回給應用端的結果集爲 [0,1],若是Mycat最早收到DB2節點的結果集,那麼返回給應用端的結果集爲 [5,6]。也就是說,相同狀況下,同一個SQL,在Mycat上執行時會有不一樣的返回結果。
在Mycat中執行分頁操做時必須顯示加上排序條件才能保證結果的正確性,下面看一下Mycat對排序分頁的處理邏輯。
假如在前面的分頁查詢中加上了排序條件(假如表數據的列名爲id)
mysql>select * from table order by id limit 2;
Mycat的處理邏輯以下圖:
在有排序呢條件的狀況下,Mycat接收到各個DB節點的返回結果後,對其進行最小堆運算,計算出全部結果集中最小的兩條記錄 [0,1] 返回給應用。
可是,當排序分頁中有 偏移量 (offset)時,處理邏輯又有不一樣。假如應用的查詢SQL以下:
mysql>select * from table order by id limit 5,2;
若是按照上述排序分頁邏輯來處理,那麼處理結果以下圖:
Mycat將各個DB節點返回的數據 [10,11], [16,17], [20,21] 通過最小堆計算後返回給應用的結果集是 [10,11]。但是,對於應用而言,該表的全部數據明明是 0-29 這30個數據的集合,limit 5,2 操做返回的結果集應該是 [5,6],若是返回 [10,11] 則是錯誤的處理邏輯。
因此Mycat在處理 有偏移量的排序分頁 時是另一套邏輯——改寫SQL 。以下圖:
Mycat在下發有 limit m,n 的SQL語句時會對其進行改寫,改寫成 limit 0, m+n 來保證查詢結果的邏輯正確性。因此,Mycat發送到後端DB上的SQL語句是
mysql>select * from table order by id limit 0,7;
各個DB返回給Mycat的結果集是
DB1: [0,1,2,3,4,10,11]
DB2: [5,6,7,8,9,16,17]
DB3: [20,21,22,23,24,25,26]
通過最小堆計算後獲得最小序列 [0,1,2,3,4,5,6] ,而後返回偏移量爲5的兩個結果爲 [5,6] 。
雖然Mycat返回了正確的結果,可是仔細推敲發現這類操做的處理邏輯是及其消耗(浪費)資源的。應用須要的結果集爲2條,Mycat中須要處理的結果數爲21條。也就是說,對於有 t 個DB節點的全分片 limit m, n 操做,Mycat須要處理的數據量爲 (m+n)*t 個。好比實際應用中有50個DB節點,要執行limit 1000,10操做,則Mycat處理的數據量爲 50500 條,返回結果集爲10,當偏移量更大時,內存和CPU資源的消耗則是數十倍增長。
若是設計使用Mycat時有分頁排序,請考慮放棄!
先看一下在單庫中JOIN中的場景。假設在某單庫中有 player 和 team 兩張表,player 表中的 team_id 字段與 team 表中的 id 字段相關聯。操做場景以下圖:
JOIN操做的SQL以下
mysql>select p_name,t_name from player p, team t where p.no = 3 and p.team_id = t.id;
此時能查詢出結果
p_name | t_name |
---|---|
Wade | Heat |
若是將這兩個表的數據分庫後,相關聯的數據可能分佈在不一樣的DB節點上,以下圖:
這個SQL在各個單獨的分片DB中都查不出結果,也就是說Mycat不能查詢出正確的結果集。
設計使用Mycat時若是要進行表JOIN操做,要確保兩個表的關聯字段具備相同的數據分佈,不然請考慮放棄!
Mycat並無根據二階段提交協議實現 XA事務,而是隻保證 prepare 階段數據一致性的 弱XA事務 ,實現過程以下:
應用開啓事務後Mycat標識該鏈接爲非自動提交,好比前端執行
mysql>begin;
Mycat不會當即把命令發送到DB節點上,等後續下發SQL時,Mycat從鏈接池獲取非自動提交的鏈接去執行。
Mycat會等待各個節點的返回結果,若是都執行成功,Mycat給該鏈接標識爲 Prepare Ready 狀態,若是有一個節點執行失敗,則標識爲 Rollback 狀態。
執行完成後Mycat等待前端發送 commit 或 rollback 命令。發送 commit 命令時,Mycat檢測當前鏈接是否爲 Prepare Ready 狀態,如果,則將 commit 命令發送到各個DB節點。
可是,這一階段是沒法保證一致性的,若是一個DB節點在 commit 時故障,而其餘DB節點 commit 成功,Mycat會一直等待故障DB節點返回結果。Mycat只有收到全部DB節點的成功執行結果纔會向前端返回 執行成功 的包,此時Mycat只能一直 waiting 直至TIMEOUT,致使事務一致性被破壞。
設計使用Mycat時若是有分佈式事務,得先看是否得保證事務得強一致性,不然請考慮放棄!