| 該帖已經(jīng)被評為精華帖 | |
|---|---|
| 作者 | 正文 |
| 發(fā)表時(shí)間:2009-03-05 今天看了“Database Sharding at Netlog, with MySQL and PHP”一文,和去年我們討論擴展的思路很類(lèi)似(不過(guò)這種分布式擴展,計算,存儲的思路都很類(lèi)似),但是這片文章的作者是在日益爆炸式增長(cháng)的用戶(hù)數據下實(shí)踐的分享,因此這里將文中的一些思想記錄下來(lái)分享一下。 Netlog擁有4000萬(wàn)活躍用戶(hù),每個(gè)月有超過(guò)5000萬(wàn)的獨立用戶(hù)訪(fǎng)問(wèn)網(wǎng)站,每個(gè)月有5億多的PV。數據量應該算是比較大的。作者是Jurriaan Persyn,他從一個(gè)開(kāi)發(fā)者角度而非DBA或者SA角度來(lái)談Netlog是如何通過(guò)數據切分來(lái)提高網(wǎng)站性能,橫向擴展數據層的。原文在:http://www.jurriaanpersyn.com/archives/2009/02/12/database-sharding-at-netlog-with-mysql-and-php/
首先,還是先談到關(guān)于數據庫在數據日益龐大的情況下一個(gè)演變過(guò)程。 第一階段:讀寫(xiě)同在一臺數據庫服務(wù)器
第二階段:讀寫(xiě)分離(可以解決讀寫(xiě)比例均衡或者讀居多的情況,但是帶入了數據復制同步的問(wèn)題)
第三階段:部分數據獨立部署結合讀寫(xiě)分離。(部分數據根據其業(yè)務(wù)獨立性情況,可以將所有的數據獨立存儲到數據庫服務(wù)器,分擔數據讀寫(xiě)壓力,前提是要求數據具有較高的業(yè)務(wù)獨立性)
第四階段:數據分拆結合讀寫(xiě)分離(三階段的增強)
第五階段:?jiǎn)?wèn)題出現,分拆也無(wú)法解決數據爆炸性增長(cháng),同時(shí)讀寫(xiě)處于同等比例。
解決問(wèn)題兩種方式:DB Scale up ,DB Scale out。前者投入以及后期擴展有限,因此需要進(jìn)行數據切分。
上圖就是將photo的數據切分到了10臺數據庫服務(wù)器上。
切分數據的兩個(gè)關(guān)鍵點(diǎn): 1. 如何根據存儲的數據內容判斷數據的存儲歸屬,也就是什么是內容的分區主鍵。 2. 采用什么算法可以根據不同的主鍵將內容存儲到不同的分區中。
分區主鍵的選擇還是要根據自身的業(yè)務(wù)場(chǎng)景來(lái)決定,Netblog選擇的是用戶(hù)ID。 采用什么方式將分區主鍵映射到對應的分區可以通過(guò)以下四種方式: 1. 根據數據表來(lái)切分。(前提就是數據獨立性較強,和前面提到的三階段類(lèi)似) 2. 基于內容區間范圍的分區。(就好比前1000個(gè)用戶(hù)的信息存儲在A服務(wù)器,1000-2000存儲在B服務(wù)器) 3. 采用Hash算法結合虛擬節點(diǎn)的方式。(這類(lèi)在memcached等等分布式場(chǎng)景中最常見(jiàn),其實(shí)也是一個(gè)難點(diǎn)),缺點(diǎn)就是在于動(dòng)態(tài)增加存儲節點(diǎn)會(huì )導致數據部分或者全部失效。 4. 目錄式的分區。最簡(jiǎn)單也是最直接的方式,key和分區的對應關(guān)系被保存,通過(guò)查找目錄可以得到分區信息。適合擴展,就是增加查詢(xún)損耗。
如何將數據分布的盡量均勻,如何平衡各個(gè)服務(wù)器之間的負載,如何在新增存儲機器和刪除存儲機器的時(shí)候不影響原有數據,同時(shí)能夠將數據均攤,都是算法的關(guān)鍵。在分布式系統中DHT(Distribute Hash Table)被很多人研究,并且有很多的論文是關(guān)于它的。
數據的橫向切分給應用帶來(lái)的問(wèn)題: 1. 跨區的數據查詢(xún)變得很困難。(對于復雜的關(guān)聯(lián)性數據查詢(xún)無(wú)法在一個(gè)請求中完成) 2. 數據一致性和引用完整性較難保證。(多物理存儲的情況下很難保證兼顧效率、可用性、一致性) 3. 數據分區之間的負載均衡問(wèn)題。(數據本身的不均衡性,訪(fǎng)問(wèn)和讀寫(xiě)的不均衡性都會(huì )給數據分區的負載均衡帶來(lái)困難) 4. 網(wǎng)絡(luò )配置的復雜性。(需要保證服務(wù)器之間的大數據量頻繁的交互和同步) 5. 數據備份策略將會(huì )變得十分復雜。 解決這些問(wèn)題當前已經(jīng)有的一些開(kāi)源項目: 1. MySql Cluster,解決讀寫(xiě)分離問(wèn)題已經(jīng)十分成熟。 2. MySql Partitioning,可以將一個(gè)大表拆分為很多小表,提高訪(fǎng)問(wèn)速度,但是限制與這些小表必須在同一臺服務(wù)器上。 3. HSCALE和Spock Proxy都是建立與MySql Proxy基礎上的開(kāi)源項目,MySql Proxy采用LUA腳本來(lái)進(jìn)行數據分區。 4. HiveDB是MySql分區框架的java實(shí)現。 5. 另外還有HyperTable,HBase,BigTable等等。
Netblog幾個(gè)需求: 1. 需要靈活的可擴展性。對于存儲增加減少需要能夠動(dòng)態(tài)的及時(shí)實(shí)施,因為數據量增長(cháng)很快,如果策略會(huì )導致數據失效或者部署需要重新啟動(dòng),則就不能滿(mǎn)足需求。 2. 不想引入全新的數據層和與原有系統不匹配的抽象層,因為并不是所有數據都需要切分,僅僅在需要的情況下通過(guò)API的方式來(lái)透明切分數據。 3. 分區的主鍵需要可配置。 4. 需要封裝API,對開(kāi)發(fā)人員透明數據切分的工作。
Netblog Sharding的實(shí)現
上圖就是Netblog的Sharding的結構圖,主要分成了三部分:Shard,Sharddb,Sharddbhost。Shard就是一個(gè)表,里面存放了部分用戶(hù)數據。Sharddb是一個(gè)表的組合就像一個(gè)虛擬的DB。Sharddbhost是具體的存儲分區。Shard,Sharddb可以根據負載的情況被移動(dòng)到不同的host中去。 對于Shard的管理,Netblog采用的是目錄查詢(xún)的管理方式。目錄信息也存儲在MySql中,同時(shí)會(huì )通過(guò)互備,Memcache,集群來(lái)確保安全性和高效性。 Shard Table API采用了多一層的映射模式來(lái)適合各種不同屬性的查詢(xún)情況。數據和記錄在數據庫中存儲除了UserID以外還有對應的ItemID,ItemID的作用就是定義了具體獲取數據的字段信息,例如關(guān)聯(lián)照片表時(shí),ItemID就是PhotoId,關(guān)聯(lián)視頻表時(shí),ItemID就是videoID。 一個(gè)獲取用戶(hù)id為26博客信息的范例: 1.Where is user 26? User 26 is on shard 5. 2.On shard 5; Give me all the $blogIDs ($itemIDs) of user 26. That user's $blogIDs are: array(10,12,30); 3.On shard 5; Give me all details about the items array(10,12,30) of user 26. Those items are: array(array('title' => "foo", 'message' => "bar"), array('title' => "milk", 'message' => "cow"));
對于Shard的管理Netblog采取的措施主要有這些: 1. 服務(wù)器之間的負載均衡根據用戶(hù)數,數據庫文件大小,讀寫(xiě)次數,cpu load等等作為參數來(lái)監控和維護。根據最后的結果來(lái)遷移數據和分流數據。 2. 移動(dòng)數據時(shí)會(huì )監控用戶(hù)是否在操作數據,防止不一致性。 3. 對于數據庫的可用性,采用集群,master-master,master-slave復制等手段。
最后通過(guò)三種技術(shù)來(lái)解決三個(gè)問(wèn)題:
1. Memcached解決shard多次查詢(xún)的效率問(wèn)題。 根據上面的范例可以看到,一次查詢(xún)現在被分割成為了三部分:shard查詢(xún),item查詢(xún),最終結果查詢(xún)。通過(guò)memcached可以緩存三部分內容,由前到后數據的穩定性以及命中率逐漸降低,同時(shí)通過(guò)結合有效期(內容存儲時(shí)效)和修改更新機制(add,update,delete觸發(fā)緩存更新),可以極大地解決效率問(wèn)題。甚至通過(guò)緩存足夠信息減少大量的數據庫交互。
2. 并行計算處理。 由于數據的分拆,有時(shí)候需要得到對于多Shard數據處理的結果匯總,因此就會(huì )將一個(gè)請求分拆為多個(gè)請求,分別交由多個(gè)服務(wù)器處理,最后將結果匯總。(類(lèi)似于Map-reduce)
3. 采用Sphinx全文搜索引擎解決多數據分區數據匯總查詢(xún),例如察看網(wǎng)站用戶(hù)的最新更新情況或者最熱門(mén)日至。這個(gè)采用單獨系統部署,通過(guò)建立全局信息索引,來(lái)查詢(xún)數據情況。
以上是技術(shù)上的全部?jì)热?,作者在最后的幾個(gè)觀(guān)點(diǎn)十分值得學(xué)習,同時(shí)也不僅僅限于數據切分,任何框架設計都可以參考。
“Don't do it, if you don't need to!" (37signals.com) "Shard early and often!" (startuplessonslearned.blogspot.com)
看起來(lái)矛盾的兩句話(huà),卻是說(shuō)出了對于數據切分的一些考慮。 首先在沒(méi)有必要的情況下就不要考慮數據切分,切分帶來(lái)的復雜性直接影響可用性,可維護性和一致性。在能夠采用Scale up的情況下,可以選擇Scale up降低框架復雜度。 另一方面,如果發(fā)現了業(yè)務(wù)增長(cháng)情況出現必須要擴展的趨勢,那么就要盡早著(zhù)手去實(shí)施和規劃擴展的工作,并且在切分和擴展過(guò)程中要不斷地去優(yōu)化和重構。
后話(huà): 其實(shí)任何架構設計首要就是簡(jiǎn)單直接,不過(guò)度設計,不濫竽充數。其實(shí)就是要平衡好:可用性、高效性、一致性、可擴展性這四者之間的關(guān)系。良性循環(huán)、應時(shí)應事作出取舍和折中。用的好要比學(xué)會(huì )用更重要,更關(guān)鍵。 | |
聯(lián)系客服