第1章 引言
隨著(zhù)互聯(lián)網(wǎng)應用的廣泛普及,海量數據的存儲和訪(fǎng)問(wèn)成為了系統設計的瓶頸問(wèn)題。對于一個(gè)大型的互聯(lián)網(wǎng)應用,每天幾十億的PV無(wú)疑對數據庫造成了相當高的負載。對于系統的穩定性和擴展性造成了極大的問(wèn)題。通過(guò)數據切分來(lái)提高網(wǎng)站性能,橫向擴展數據層已經(jīng)成為架構研發(fā)人員首選的方式。水平切分數據庫,可以降低單臺機器的負載,同時(shí)最大限度的降低了了宕機造成的損失。通過(guò)負載均衡策略,有效的降低了單臺機器的訪(fǎng)問(wèn)負載,降低了宕機的可能性;通過(guò)集群方案,解決了數據庫宕機帶來(lái)的單點(diǎn)數據庫不能訪(fǎng)問(wèn)的問(wèn)題;通過(guò)讀寫(xiě)分離策略更是最大限度了提高了應用中讀?。≧ead)數據的速度和并發(fā)量。目前國內的大型互聯(lián)網(wǎng)應用中,大量的采用了這樣的數據切分方案,Taobao,Alibaba,Tencent,它們大都實(shí)現了自己的分布式數據訪(fǎng)問(wèn)層(DDAL)。以實(shí)現方式和實(shí)現的層次來(lái)劃分,大概分為兩個(gè)層次(Java應用為例):JDBC層的封裝,ORM框架層的實(shí)現。就JDBC層的直接封裝而言,現在國內發(fā)展較好的一個(gè)項目是被稱(chēng)作“變形蟲(chóng)”(Amoeba)的項目,由阿里集團的研究院開(kāi)發(fā),現在仍然處于測試階段(beta版),其運行效率和生產(chǎn)時(shí)效性有待考究。就ORM框架層的實(shí)現而言,比如Taobao的基于ibatis和Spring的的分布式數據訪(fǎng)問(wèn)層,已有多年的應用,運行效率和生產(chǎn)實(shí)效性得到了開(kāi)發(fā)人員和用戶(hù)的肯定。本文就是以ORM框架層為基礎而實(shí)現的分布式數據訪(fǎng)問(wèn)層。本課題的難點(diǎn)在于分庫后,路由規則的制定和選擇以及后期的擴展性,比如:如何做到用最少的數據遷移量,達到擴充數據庫容量(增加機器節點(diǎn))的目的。核心問(wèn)題將圍繞數據庫分庫分表的路由規則和負載均衡策略展開(kāi)。
第2章 基本原理和概念
2.1基本原理:
人類(lèi)認知問(wèn)題的過(guò)程總是這樣的:what(什么)-?why(為什么)-?how(怎么
做),接下來(lái),本文將就這三個(gè)問(wèn)題展開(kāi)討論和研究:
2.1.1什么是數據切分
"Shard" 這個(gè)詞英文的意思是"碎片",而作為數據庫相關(guān)的技術(shù)用語(yǔ),似乎最早見(jiàn)于大型多人在線(xiàn)角色扮演游戲中。"Sharding" 姑且稱(chēng)之為"分片"。Sharding 不是一門(mén)新技術(shù),而是一個(gè)相對簡(jiǎn)樸的軟件理念。眾所周知,MySQL 5 之后才有了數據表分區功能,那么在此之前,很多 MySQL 的潛在用戶(hù)都對 MySQL 的擴展性有所顧慮,而是否具備分區功能就成了衡量一個(gè)數據庫可擴展性與否的一個(gè)關(guān)鍵指標(當然不是唯一指標)。數據庫擴展性是一個(gè)永恒的話(huà)題,MySQL 的推廣者經(jīng)常會(huì )被問(wèn)到:如在單一數據庫上處理應用數據捉襟見(jiàn)肘而需要進(jìn)行分區化之類(lèi)的處理,是如何辦到的呢? 答案是:Sharding。 Sharding 不是一個(gè)某個(gè)特定數據庫軟件附屬的功能,而是在具體技術(shù)細節之上的抽象處理,是水平擴展(Scale Out,亦或橫向擴展、向外擴展)的解決方案,其主要目的是為突破單節點(diǎn)數據庫服務(wù)器的 I/O 能力限制,解決數據庫擴展性問(wèn)題。
通過(guò)一系列的切分規則將數據水平分布到不同的DB或table中,在通過(guò)相應的DB路由 或者 table路由規則找到需要查詢(xún)的具體的DB或者table,以進(jìn)行Query操作。這里所說(shuō)的“sharding”通常是指“水平切分”, 這也是本文討論的重點(diǎn)。具體將有什么樣的切分方式呢和路由方式呢?行文至此,讀者難免有所疑問(wèn),接下來(lái)舉個(gè)簡(jiǎn)單的例子:我們針對一個(gè)Blog應用中的日志來(lái)說(shuō)明,比如日志文章(article)表有如下字段:

面對這樣的一個(gè)表,我們怎樣切分呢?怎樣將這樣的數據分布到不同的數據庫中的表中去呢?其實(shí)分析blog的應用,我們不難得出這樣的結論:blog的應用中,用戶(hù)分為兩種:瀏覽者和blog的主人。瀏覽者瀏覽某個(gè)blog,實(shí)際上是在一個(gè)特定的用戶(hù)的blog下進(jìn)行瀏覽的,而blog的主人管理自己的blog,也同樣是在特定的用戶(hù)blog下進(jìn)行操作的(在自己的空間下)。所謂的特定的用戶(hù),用數據庫的字段表示就是“user_id”。就是這個(gè)“user_id”,它就是我們需要的分庫的依據和規則的基礎。我們可以這樣做,將user_id為 1~10000的所有的文章信息放入DB1中的article表中,將user_id為10001~20000的所有文章信息放入DB2中的 article表中,以此類(lèi)推,一直到DBn。 這樣一來(lái),文章數據就很自然的被分到了各個(gè)數據庫中,達到了數據切分的目的。接下來(lái)要解決的問(wèn)題就是怎樣找到具體的數據庫呢?其實(shí)問(wèn)題也是簡(jiǎn)單明顯的,既然分庫的時(shí)候我們用到了區分字段user_id,那么很自然,數據庫路由的過(guò)程當然還是少不了 user_id的??紤]一下我們剛才呈現的blog應用,不管是訪(fǎng)問(wèn)別人的blog還是管理自己的blog,總之我都要知道這個(gè)blog的用戶(hù)是誰(shuí)吧,也就是我們知道了這個(gè)blog的user_id,就利用這個(gè)user_id,利用分庫時(shí)候的規則,反過(guò)來(lái)定位具體的數據庫,比如user_id是234,利用該才的規則,就應該定位到DB1,假如user_id是12343,利用該才的規則,就應該定位到DB2。以此類(lèi)推,利用分庫的規則,反向的路由到具體的DB,這個(gè)過(guò)程我們稱(chēng)之為“DB路由”。
當然考慮到數據切分的DB設計必然是非常規,不正統的DB設計。那么什么樣的DB設計是正統的DB設計呢?
我們平常規規矩矩用的基本都是。平常我們會(huì )自覺(jué)的按照范式來(lái)設計我們的數據庫,負載高點(diǎn)可能考慮使用相關(guān)的Replication機制來(lái)提高讀寫(xiě)的吞吐和性能,這可能已經(jīng)可以滿(mǎn)足很多需求,但這套機制自身的缺陷還是比較顯而易見(jiàn)的(下文會(huì )提及)。上面提到的“自覺(jué)的按照范式設計”??紤]到數據切分的DB設計,將違背這個(gè)通常的規矩和約束,為了切分,我們不得不在數據庫的表中出現冗余字段,用作區分字段或者叫做分庫的標記字段,比如上面的article的例子中的user_id這樣的字段(當然,剛才的例子并沒(méi)有很好的體現出user_id的冗余性,因為user_id這個(gè)字段即使就是不分庫,也是要出現的,算是我們撿了便宜吧)。當然冗余字段的出現并不只是在分庫的場(chǎng)景下才出現的,在很多大型應用中,冗余也是必須的,這個(gè)涉及到高效DB的設計,本文不再贅述。
2.1.2為什么要數據切分
上面對什么是數據切分做了個(gè)概要的描述和解釋?zhuān)x者可能會(huì )疑問(wèn),為什么需要數據切分呢?像 Oracle這樣成熟穩定的數據庫,足以支撐海量數據的存儲與查詢(xún)了?為什么還需要數據切片呢?的確,Oracle的DB確實(shí)很成熟很穩定,但是高昂的使用費用和高端的硬件支撐不是每一個(gè)公司能支付的起的。試想一下一年幾千萬(wàn)的使用費用和動(dòng)輒上千萬(wàn)元的小型機作為硬件支撐,這是一般公司能支付的起的嗎?即使就是能支付的起,假如有更好的方案,有更廉價(jià)且水平擴展性能更好的方案,我們?yōu)槭裁床贿x擇呢?
但是,事情總是不盡人意。平常我們會(huì )自覺(jué)的按照范式來(lái)設計我們的數據庫,負載高點(diǎn)可能考慮使用相關(guān)的Replication機制來(lái)提高讀寫(xiě)的吞吐和性能,這可能已經(jīng)可以滿(mǎn)足很多需求,但這套機制自身的缺陷還是比較顯而易見(jiàn)的。首先它的有效很依賴(lài)于讀操作的比例,Master往往會(huì )成為瓶頸所在,寫(xiě)操作需要順序排隊來(lái)執行,過(guò)載的話(huà)Master首先扛不住,Slaves的數據同步的延遲也可能比較大,而且會(huì )大大耗費CPU的計算能力,因為write操作在Master上執行以后還是需要在每臺slave機器上都跑一次。這時(shí)候 Sharding可能會(huì )成為雞肋了。 Replication搞不定,那么為什么Sharding可以工作呢?道理很簡(jiǎn)單,因為它可以很好的擴展。我們知道每臺機器無(wú)論配置多么好它都有自身的物理上限,所以當我們應用已經(jīng)能觸及或遠遠超出單臺機器的某個(gè)上限的時(shí)候,我們惟有尋找別的機器的幫助或者繼續升級的我們的硬件,但常見(jiàn)的方案還是橫向擴展, 通過(guò)添加更多的機器來(lái)共同承擔壓力。我們還得考慮當我們的業(yè)務(wù)邏輯不斷增長(cháng),我們的機器能不能通過(guò)線(xiàn)性增長(cháng)就能滿(mǎn)足需求?Sharding可以輕松的將計算,存儲,I/O并行分發(fā)到多臺機器上,這樣可以充分利用多臺機器各種處理能力,同時(shí)可以避免單點(diǎn)失敗,提供系統的可用性,進(jìn)行很好的錯誤隔離。
綜合以上因素,數據切分是很有必要的,且我們在此討論的數據切分也是將MySql作為背景的?;诔杀镜目紤],很多公司也選擇了Free且Open的MySql。對MySql有所了解的開(kāi)發(fā)人員可能會(huì )知道,MySQL 5 之后才有了數據表分區功能,那么在此之前,很多 MySQL 的潛在用戶(hù)都對 MySQL 的擴展性有所顧慮,而是否具備分區功能就成了衡量一個(gè)數據庫可擴展性與否的一個(gè)關(guān)鍵指標(當然不是唯一指標)。數據庫擴展性是一個(gè)永恒的話(huà)題,MySQL 的推廣者經(jīng)常會(huì )被問(wèn)到:如在單一數據庫上處理應用數據捉襟見(jiàn)肘而需要進(jìn)行分區化之類(lèi)的處理,是如何辦到的呢? 答案也是Sharding,也就是我們所說(shuō)的數據切分方案。
我們用免費的MySQL和廉價(jià)的Server甚至是PC做集群,達到小型機+大型商業(yè)DB的效果,減少大量的資金投入,降低運營(yíng)成本,何樂(lè )而不為呢?所以,我們選擇Sharding,擁抱Sharding。
2.1.3怎么做到數據切分
說(shuō)到數據切分,再次我們講對數據切分的方法和形式進(jìn)行比較詳細的闡述和說(shuō)明。
數據切分可以是物理 上的,對數據通過(guò)一系列的切分規則將數據分布到不同的DB服務(wù)器上,通過(guò)路由規則路由訪(fǎng)問(wèn)特定的數據庫,這樣一來(lái)每次訪(fǎng)問(wèn)面對的就不是單臺服務(wù)器了,而是N臺服務(wù)器,這樣就可以降低單臺機器的負載壓力。
數 據切分也可以是數據庫內的 ,對數據通過(guò)一系列的切分規則,將數據分布到一個(gè)數據庫的不同表中,比如將article分為article_001,article_002等子表,若干個(gè)子表水平拼合有組成了邏輯上一個(gè)完整的article表,這樣做的目的其實(shí)也是很簡(jiǎn)單的。 舉個(gè)例子說(shuō)明,比如article表中現在有5000w條數據,此時(shí)我們需要在這個(gè)表中增加(insert)一條新的數據,insert完畢后,數據庫會(huì )針對這張表重新建立索引,5000w行數據建立索引的系統開(kāi)銷(xiāo)還是不容忽視的。但是反過(guò)來(lái),假如我們將這個(gè)表分成100 個(gè)table呢,從article_001一直到article_100,5000w行數據平均下來(lái),每個(gè)子表里邊就只有50萬(wàn)行數據,這時(shí)候我們向一張只有50w行數據的table中insert數據后建立索引的時(shí)間就會(huì )呈數量級的下降,極大了提高了DB的運行時(shí)效率,提高了DB的并發(fā)量。當然分表的好處還不知這些,還有諸如寫(xiě)操作的鎖操作等,都會(huì )帶來(lái)很多顯然的好處。
綜上,分庫降低了單點(diǎn)機器的負載;分表,提高了數據操作的效率,尤其是Write操作的效率。 行文至此我們依然沒(méi)有涉及到如何切分的問(wèn)題。接下來(lái),我們將對切分規則進(jìn)行詳盡的闡述和說(shuō)明。
上文中提到,要想做到數據的水平切分,在每一個(gè)表中都要有相冗余字符 作為切分依據和標記字段,通常的應用中我們選用user_id作為區分字段,基于此就有如下三種分庫的方式和規則: (當然還可以有其他的方式)
按號段分:
(1) user_id為區分,1~1000的對應DB1,1001~2000的對應DB2,以此類(lèi)推;
優(yōu)點(diǎn):可部分遷移
缺點(diǎn):數據分布不均
(2)hash取模分:
對user_id進(jìn)行hash(或者如果user_id是數值型的話(huà)直接使用user_id 的值也可),然后用一個(gè)特定的數字,比如應用中需要將一個(gè)數據庫切分成4個(gè)數據庫的話(huà),我們就用4這個(gè)數字對user_id的hash值進(jìn)行取模運算,也就是user_id%4,這樣的話(huà)每次運算就有四種可能:結果為1的時(shí)候對應DB1;結果為2的時(shí)候對應DB2;結果為3的時(shí)候對應DB3;結果為0的時(shí)候對應DB4,這樣一來(lái)就非常均勻的將數據分配到4個(gè)DB中。
優(yōu)點(diǎn):數據分布均勻
缺點(diǎn):數據遷移的時(shí)候麻煩,不能按照機器性能分攤數據
(3)在認證庫中保存數據庫配置
就是建立一個(gè)DB,這個(gè)DB單獨保存user_id到DB的映射關(guān)系,每次訪(fǎng)問(wèn)數據庫的時(shí)候都要先查詢(xún)一次這個(gè)數據庫,以得到具體的DB信息,然后才能進(jìn)行我們需要的查詢(xún)操作。
優(yōu)點(diǎn):靈活性強,一對一關(guān)系
缺點(diǎn):每次查詢(xún)之前都要多一次查詢(xún),性能大打折扣
以上就是通常的開(kāi)發(fā)中我們選擇的三種方式,有些復雜的項目中可能會(huì )混合使用這三種方式。 通過(guò)上面的描述,我們對分庫的規則也有了簡(jiǎn)單的認識和了解。當然還會(huì )有更好更完善的分庫方式,還需要我們不斷的探索和發(fā)現。
第3章 本課題研究的基本輪廓
上面的文字,我們按照人類(lèi)認知事物的規律,what?why?how這樣的方式闡述了數據庫切分的一些概念和意義以及對一些常規的切分規則做了概要的介紹。本課題所討論的分布數據層并不僅僅如此,它是一個(gè)完整的數據層解決方案,它到底是什么樣的呢?接下來(lái)的文字,我將詳細闡述本研究課題的完整思想和實(shí)現方式。
分布式數據方案提供功能如下:
(1)提供分庫規則和路由規則(RouteRule簡(jiǎn)稱(chēng)RR),將上面的說(shuō)明中提到的三中切分規則直接內嵌入本系統,具體的嵌入方式在接下來(lái)的內容中進(jìn)行詳細的說(shuō)明和論述;
(2)引入集群(Group)的概念,保證數據的高可用性;
(3)引入負載均衡策略(LoadBalancePolicy簡(jiǎn)稱(chēng)LB);
(4)引入集群節點(diǎn)可用性探測機制,對單點(diǎn)機器的可用性進(jìn)行定時(shí)的偵測,以保證LB策略的正確實(shí)施,以確保系統的高度穩定性;
(5)引入讀/寫(xiě)分離,提高數據的查詢(xún)速度;
僅僅是分庫分表的數據層設計也是不夠完善的,當某個(gè)節點(diǎn)上的DB服務(wù)器出現了宕機的情況的時(shí)候,會(huì )是什么樣的呢?是的,我們采用了數據庫切分方案,也就是說(shuō)有N太機器組成了一個(gè)完整的DB ,如果有一臺機器宕機的話(huà),也僅僅是一個(gè)DB的N分之一的數據不能訪(fǎng)問(wèn)而已,這是我們能接受的,起碼比切分之前的情況好很多了,總不至于整個(gè)DB都不能訪(fǎng)問(wèn)。一般的應用中,這樣的機器故障導致的數據無(wú)法訪(fǎng)問(wèn)是可以接受的,假設我們的系統是一個(gè)高并發(fā)的電子商務(wù)網(wǎng)站呢?單節點(diǎn)機器宕機帶來(lái)的經(jīng)濟損失是非常嚴重的。也就是說(shuō),現在我們這樣的方案還是存在問(wèn)題的,容錯性能是經(jīng)不起考驗的。當然了,問(wèn)題總是有解決方案的。我們引入集群的概念,在此我稱(chēng)之為Group,也就是每一個(gè)分庫的節點(diǎn)我們引入多臺機器,每臺機器保存的數據是一樣的,一般情況下這多臺機器分攤負載,當出現宕機情況,負載均衡器將分配負載給這臺宕機的機器。這樣一來(lái),
就解決了容錯性的問(wèn)題。所以我們引入了集群的概念,并將其內嵌入我們的框架中,成為框架的一部分。

如上圖所示,整個(gè)數據層有Group1,Group2,Group3三個(gè)集群組成,這三個(gè)集群就是數據水平切分的結果,當然這三個(gè)集群也就組成了一個(gè)包含完整數據的DB。每一個(gè)Group包括1個(gè)Master(當然Master也可以是多個(gè))和 N個(gè)Slave,這些Master和Slave的數據是一致的。比如Group1中的一個(gè)slave發(fā)生了宕機現象,那么還有兩個(gè)slave是可以用的,這樣的模型總是不會(huì )造成某部分數據不能訪(fǎng)問(wèn)的問(wèn)題,除非整個(gè) Group里的機器全部宕掉,但是考慮到這樣的事情發(fā)生的概率非常?。ǔ鞘菙嚯娏?,否則不易發(fā)生吧)。
在沒(méi)有引入集群以前,我們的一次查詢(xún)的過(guò)程大致如下:請求數據層,并傳遞必要的分庫區分字段(通常情況下是user_id)?數據層根據區分字段Route到具體的DB?在這個(gè)確定的DB內進(jìn)行數據操作。 這是沒(méi)有引入集群的情況,當時(shí)引入集群會(huì )是什么樣子的呢?看圖一即可得知,我們的路由器上規則和策略其實(shí)只能路由到具體的Group,也就是只能路由到一個(gè)虛擬的Group,這個(gè)Group并不是某個(gè)特定的物理服務(wù)器。接下來(lái)需要做的工作就是找到具體的物理的DB服務(wù)器,以進(jìn)行具體的數據操作?;谶@個(gè)環(huán)節的需求,我們引入了負載均衡器的概念(LB)。負載均衡器的職責就是定位到一臺具體的DB服務(wù)器。具體的規則如下:負載均衡器會(huì )分析當前sql的讀寫(xiě)特性,如果是寫(xiě)操作或者是要求實(shí)時(shí)性很強的操作的話(huà),直接將查詢(xún)負載分到Master,如果是讀操作則通過(guò)負載均衡策略分配一個(gè)Slave。我們的負載均衡器的主要研究放向也就是負載分發(fā)策略,通常情況下負載均衡包括隨機負載均衡和加權負載均衡 。 隨機負載均衡很好理解,就是從N個(gè)Slave中隨機選取一個(gè)Slave。這樣的隨機負載均衡是不考慮機器性能的,它默認為每臺機器的性能是一樣的。假如真實(shí)的情況是這樣的,這樣做也是無(wú)可厚非的。假如實(shí)際情況并非如此呢?每個(gè)Slave的機器物理性能和配置不一樣的情況,再使用隨機的不考慮性能的負載均衡,是非常不科學(xué)的,這樣一來(lái)會(huì )給機器性能差的機器帶來(lái)不必要的高負載,甚至帶來(lái)宕機的危險, 同時(shí)高性能的數據庫服務(wù)器也不能充分發(fā)揮其物理性能?;诖丝紤]從,我們引入了加權負載均衡,也就是在我們的系統內部通過(guò)一定的接口,可以給每臺DB服務(wù)器分配一個(gè)權值,然后再運行時(shí)LB根據權值在集群中的比重,分配一定比例的負載給該DB服務(wù)器。當然這樣的概念的引入,無(wú)疑增大了系統的復雜性和可維護性。有得必有失,我們也沒(méi)有辦法逃過(guò)的。
有了分庫,有了集群,有了負載均衡器,是不是就萬(wàn)事大吉了呢? 事情遠沒(méi)有我們想象的那么簡(jiǎn)單。雖然有了這些東西,基本上能保證我們的數據層可以承受很大的壓力 ,但是這樣的設計并不能完全規避數據庫宕機的危害。假如Group1中的slave2 宕機了,那么系統的LB并不能得知,這樣的話(huà)其實(shí)是很危險的,因為L(cháng)B不知道,它還會(huì )以為slave2為可用狀態(tài),所以還是會(huì )給slave2分配負載。這樣一來(lái),問(wèn)題就出來(lái)了,客戶(hù)端很自然的就會(huì )發(fā)生數據操作失敗的錯誤或者異常。這樣是非常不友好的!怎樣解決這樣的問(wèn)題呢? 我們引入集群節點(diǎn)的可用性探測機制 ,或者是可用性的數據推送機制 。這兩種機制有什么不同呢?首先說(shuō)探測機制吧,顧名思義,探測即使,就是我的數據層客戶(hù)端,不定時(shí)對集群中各個(gè)數據庫進(jìn)行可用性的嘗試,實(shí)現原理就是嘗試性鏈接,或者數據庫端口的嘗試性訪(fǎng)問(wèn),都可以做到,當然也可以用JDBC嘗試性鏈接,利用Java的Exception機制進(jìn)行可用性的判斷,具體的會(huì )在后面的文字中提到。那數據推送機制又是什么呢?其實(shí)這個(gè)就要放在現實(shí)的應用場(chǎng)景中來(lái)討論這個(gè)問(wèn)題了,一般情況下應用的DB 數據庫宕機的話(huà)我相信DBA肯定是知道的,這個(gè)時(shí)候DBA手動(dòng)的將數據庫的當前狀態(tài)通過(guò)程序的方式推送到客戶(hù)端,也就是分布式數據層的應用端,這個(gè)時(shí)候在更新一個(gè)本地的DB狀態(tài)的列表。并告知LB,這個(gè)數據庫節點(diǎn)不能使用,請不要給它分配負載。一個(gè)是主動(dòng)的監聽(tīng)機制,一個(gè)是被動(dòng)的被告知的機制。兩者各有所長(cháng)。但是都可以達到同樣的效果。這樣一來(lái)剛才假設的問(wèn)題就不會(huì )發(fā)生了,即使就是發(fā)生了,那么發(fā)生的概率也會(huì )降到最低。
上面的文字中提到的Master和Slave ,我們并沒(méi)有做太多深入的講解。如圖一所示,一個(gè)Group由1個(gè)Master和N個(gè)Slave組成。為什么這么做呢?其中Master負責寫(xiě)操作的負載,也就是說(shuō)一切寫(xiě)的操作都在Master上進(jìn)行,而讀的操作則分攤到Slave上進(jìn)行。這樣一來(lái)的可以大大提高讀取的效率。在一般的互聯(lián)網(wǎng)應用中,經(jīng)過(guò)一些數據調查得出結論,讀/寫(xiě)的比例大概在 10:1左右 ,也就是說(shuō)大量的數據操作是集中在讀的操作,這也就是為什么我們會(huì )有多個(gè)Slave的原因。但是為什么要分離讀和寫(xiě)呢?熟悉DB的研發(fā)人員都知道,寫(xiě)操作涉及到鎖的問(wèn)題,不管是行鎖還是表鎖還是塊鎖,都是比較降低系統執行效率的事情。我們這樣的分離是把寫(xiě)操作集中在一個(gè)節點(diǎn)上,而讀操作其其他的N個(gè)節點(diǎn)上進(jìn)行,從另一個(gè)方面有效的提高了讀的效率,保證了系統的高可用性。讀寫(xiě)分離也會(huì )引入新的問(wèn)題,比如我的Master上的數據怎樣和集群中其他的Slave機器保持數據的同步和一致呢?這個(gè)是我們不需要過(guò)多的關(guān)注的問(wèn)題,MySql的Proxy機制可以幫助我們做到這點(diǎn),由于Proxy機制與本課題相關(guān)性不是太強,
在這里不做詳細介紹。
綜上所述,本課題中所研究的分布式數據層的大體功能就是如此。以上是對基本原理的一些討論和闡述。接下來(lái)就系統設計層面,進(jìn)行深入的剖析和研究。
第4章 系統設計
4.1系統實(shí)現層面的選擇
在引言部分中提到,該系統的實(shí)現層面有兩種選擇,一種是基于JDBC層面上的選擇,一種是基于現有數據持久層框架層面上的選擇,比如Hibernate,ibatis。兩種層面各有長(cháng)處,也各有不足之處?;贘DBC層面上的系統實(shí)現,系統開(kāi)發(fā)難度和后期的使用難度都將大大提高。大大增加了系統的開(kāi)發(fā)費用和維護費用。本課題的定位是在成型的ibatis持久層框架的基礎上進(jìn)行上層的封裝,而不是對ibatis源碼的直接修改,這樣一來(lái)使本系統不會(huì )對現有框架有太多的侵入性,從而也增加了使用的靈活性。之所以選擇ibatis,原因如下:
(1)ibatis的學(xué)習成本非常低,熟練的Java Programmer可在非常的短時(shí)間內熟練使用ibatis;
(2)ibatis是輕量級的ORM,只是簡(jiǎn)單的完成了RO,OR的映射,其查詢(xún)語(yǔ)句也是通過(guò)配置文件sql-map.xml文件在原生sql的層面進(jìn)行簡(jiǎn)單的配置,也就是說(shuō)我們沒(méi)有引入諸如Hibernate那樣的HQL的概念,從而增強了 sql的可控性,優(yōu)秀的DBA可以很好的從sql的層面對sql進(jìn)行優(yōu)化,使數據層的應用有很強的可控性。Hibernate雖然很強大,但是由于 Hibernate是OR的一個(gè)重型封裝,且引入HQL的概念,不便于DBA團隊對sql語(yǔ)句的控制和性能的調優(yōu)。
基于以上兩點(diǎn)理由,本課題在ORM的產(chǎn)品的選擇上選擇了易學(xué)易用且輕量級的持久層框架ibatis。下面的討論也都是特定于ibatis的基礎上的討論。
4.2其他開(kāi)源框架的選擇
在一些大型的Java應用中,我們通常會(huì )采用Spring這樣的開(kāi)源框架,尤其是 IoC(DI)這部分,有效的幫助開(kāi)發(fā)人員管理對象的依賴(lài)關(guān)系和層次,降低系統各層次之間的實(shí)體耦合。Spring的優(yōu)點(diǎn)和用處我相信這是開(kāi)發(fā)人員眾所周知的,在此不再贅述。本課題的數據層也將采用Spring做為IoC(DI)的框架。
4.3系統開(kāi)發(fā)技術(shù)和工具介紹
開(kāi)發(fā)語(yǔ)言:Java JDK1.5
集成開(kāi)發(fā)環(huán)境:Eclipse 3.3.4
Web環(huán)境下測試服務(wù)器:JBoss 4.2
構建工具:淘寶自行研發(fā)的構建工具Antx(類(lèi)似于Maven),當然也可以用Maven
依賴(lài)的開(kāi)源Jar:Spring2.0,ibaits,commons-configuration(讀取配置文件),log4j,junit等
第5章 系統分析(待續。。)
聯(lián)系客服