死磕MyCat使用篇之第一篇

基本概念

直接介紹概念太枯燥了,還是拿個和背景篇相似的例子介紹
業務場景:客戶完成下單,快遞員接受並更新運單狀態,客戶可以隨時查看運單狀態的任務。一票快遞可能有多個子母件。同時,我們需要標記每個運單的狀態,運單狀態的解釋和含義保存在運單狀態字典表中。
因此,我們需要建立如下表:

死磕MyCat使用篇之第一篇

我們現在按照業務將數據庫垂直拆分成運單庫(單表2000tps,6000W數據),快遞員庫(單表1500tps,100W數據),客戶庫(單表1500tps,1000W數據記錄);假設每個MySQL數據庫單表不能超過2000W數據,單表不能超過1000tps。那麼運單庫則需要分成3片,客戶庫需要分成2片,統一由MyCat管理。如下圖所示:

死磕MyCat使用篇之第一篇

1.邏輯庫

MyCat作爲一箇中間件,對應用應爲無感知的。
應用訪問MyCat,根據之前所述,應用感知到後臺只是一個(或者多個,和訪問MySQL實例一樣)數據庫(假設只有一個數據庫,這個庫叫SF,裏面有運單相關表,快遞員相關表和客戶相關表);這裏MyCat的數據庫就是邏輯庫。訪問MyCat,結果應該如下面所示

死磕MyCat使用篇之第一篇

雖然其中的表可能存在於不同的庫,但是表面上,他們屬於同一個MyCat實例中的同一個邏輯庫。所以,雖然上面的架構圖顯示他們不在同一個數據庫,但是在MyCat中,他們在同一個邏輯庫。
2.邏輯表

在邏輯庫下的表就是邏輯表。邏輯表可以分片,也可以不分片。
orders表明顯是要分片的表,但是在MyCat看來,他們雖然分佈在不同的分片節點上(分佈在不同的MySQL數據庫上),但仍視爲是同一個邏輯表,在同一個邏輯庫裏。
2.1分片表

分片表,是指那些原有的很大數據的表,需要切分到多個數據庫的表,這樣,每個分片都有一部分數據,所有分片構成了完整的數據。分片表都有自己的分片規則,根據分片規則確定分片。
配置裏面,如下配置:

<table name="orders" primaryKey="id" dataNode="test$1-2" rule="mod-long">
</table>

意思就是用mod-long規則根據主鍵id將運單表orders分割到test1,test2這兩個數據庫(分片節點)上。
請求情況1:

select * from orders where id = 1;

對於分片表的查詢,如果按照分片列查詢,則請求只會被髮送到一個分片上。
請求情況2:

select * from orders where id < 100 and id > 0;

對於分片表的查詢,如果按照分片列範圍(在字段類型支持範圍的情況下)查詢,則請求會根據分片規則計算兩個邊界值,然後將請求發送到對應結果的分片上,併合並每個分片的結果。
請求情況3:

select * from orders where initialpoint = 'Beijing';

像這種根據非分片列查詢的情況,請求會被髮送到所有分片上,併合並每個分片的結果。
請求情況4:
請求爲更新類型的sql語句,與查詢的三種情況相同處理。
2.2 非分片表

一個數據庫中並不是所有的表都很大,某些表是可以不用進行切分的,非分片是相對分片表來說的,就是那些不需要進行數據切分的表。
例如:

<table name="courier" primaryKey="id" dataNode="test3">
</table>

意思就是快遞員表不用分片,保存在test3這個分片節點上。
對於非分片表的操作和對普通數據庫的一樣,因爲不涉及到分佈式數據庫。
2.3 ER表

關係型數據庫是基於實體關係模型(Entity-Relationship Model)之上,通過其描述了真實世界中事物與關係,Mycat中的ER表即是來源於此。根據這一思路,提出了基於E-R關係的數據分片策略,子表的記錄與所關聯的父表記錄存放在同一個數據分片上,即子表依賴於父表,通過表分組(Table Group)保證數據Join不會跨庫操作。
表分組(Table Group)是解決跨分片數據join的一種很好的思路,也是數據切分規劃的重要一條規則。
如下:

<!-- 運單表,對主鍵id對2取模 -->
<table name="orders" primaryKey="id" dataNode="test$1-2" rule="mod-long">
    <!-- 運單子母件表,運單表的子表,order_id與orders的id列對應 -->
    <childTable name="orders_cargo" joinKey="order_id" parentKey="id">
    </childTable>        
</table>

運單表爲分片表,運單表和運單子母件表爲一對多關係,可以做成父子表。
對於子表的sql請求,都是通過joinKey對應到父表對應字段後,按照之前分片表的規則進行處理。
2.4 全局表

一個真實的業務系統中,往往存在大量的類似字典表的表,這些表基本上很少變動,字典表具有以下幾個特性:

變動不頻繁
數據量總體變化不大
數據規模不大,很少有超過數十萬條記錄。

對於這類的表,在分片的情況下,當業務表因爲規模而進行分片以後,業務表與這些附屬的字典表之間的關聯,就成了比較棘手的問題,所以Mycat中通過數據冗餘來解決這類表的join,即所有的分片都有一份數據的拷貝,所有將字典表或者符合字典表特性的一些表定義爲全局表。
數據冗餘是解決跨分片數據join的一種很好的思路,也是數據切分規劃的另外一條重要規則
比如:

<!-- 運單狀態信息表,公共表,放在和運單表同樣的分片上 -->
<table name="order_status_interception" primaryKey="id" type="global" dataNode="test$1-2">
</table>

運單狀態信息字典表,只是註釋每種運單狀態,就是典型的字典表,與分片表orders爲多對一的關係。
對於全局表,所有的查詢請求,只會發送到其中一個全局表分片上執行,所有的更新請求,會在每個全局表分片上執行。
2.5 如何決定?

根據之前的描述,我們可以推斷出,對於分片表的修改和查詢,如果是按照分片字段進行查找的話,則請求會被轉發到一個分片上。如果不是按照分片字段的話,就會把請求發到每一個分片上進行查找。所以,分片字段的選擇比較重要!對於全局表,相當於在每個分片上有一份相同的複製,修改請求會在每一個分片上執行,但是查詢只會落到一個分片上。所以,全局表儘量是不會改變的而且是需要和分片表做Join操作的,如果經常改變或者不需要做join,最好還是做成非分片表。

先拋出了這幾種邏輯表的概念,大家先有個印象。現在我們結合具體實際討論如何決定表的類型。

首先,orders表可定是分片表。orders_cargo表是子母件表,一個order可能有多個子母件,所以,最好把orders_cargo作爲orders的子表。
這種情況下,orders與orders_cargo按照對應鍵(就是子表按照哪個鍵與主表的哪個鍵對應進行分片。比如orders_cargo就是order_id與orders的id對應。這是以order_id與orders的id進行join結果就是對的)join結果也是正確的。

死磕MyCat使用篇之第一篇

一對n場景架構
像這種簡單的從屬關係一對n的表,我們處理起來很簡單,一般將它們按照需要做join的鍵設爲父子表即可。

但是下面的場景很麻煩,比如快遞員與運單就是多對多的關係,客戶對於運單也是多對多的關係(一個收方,一個寄方)。我們既有快遞員需要查看自己的所有運單的場景和客戶查看自己所有運單的場景。相對的,我們也有查看一個運單涉及到的快遞員還有客戶的場景。
customer表(客戶表)以及courier表(快遞員表)因爲與分片表orders之間不做join操作,所以不用作爲公共表。
首先,關係表可以作爲公共表,這樣的話,涉及到與分片表的join操作沒有限制,因爲在每個分片,公共表都是完整的。但是,關係表的更新很頻繁,我們可能不能忍受每更新一次關係表就跑到每個分片上都更新一次(性能,可靠性考慮)。
那麼作爲運單的子表呢?那麼查找一個運單涉及到的快遞員還有客戶就比較簡單。因爲根據運單號(也就是分片id)查詢,MyCat就會根據分片規則給他定位到具體分片,而不是去按分片搜索。

死磕MyCat使用篇之第一篇

這裏寫圖片描述
但是相應的,快遞員查看自己所有運單的場景就比較慢,因爲請求是發送到每一個分片上查找。
死磕MyCat使用篇之第一篇

這裏寫圖片描述
作爲快遞員的子表也有同樣的缺陷。
還有一種方法,就是這種關係表同時作爲運單和快遞員的子表。但是這樣,目前需要應用自己去做雙寫。MyCat目前還沒實現這種。當然,我覺得這是一個我們自己可以根據需要改進的地方。MyCat中間件根據關係冗餘表關係進行雙寫

另外,究竟取哪種方法,都是從業務出發去考慮的。在這裏,如果從快遞員出發去查找以及從運單出發去查找的業務壓力差不多大的話,那麼最好就採用關係表同時作爲運單和客戶的子表這種方法。然後將快遞員和運單的業務獨立,每個業務應用都去維護自己的關係表,同時通過消息隊列來保持關係表之間的一致性。這樣也不失爲一種方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章