從 Shard 到 Sharding
"Shard" 這個(gè)詞英文的意思是"碎片",而作為數(shù)據(jù)庫(kù)相關(guān)的技術(shù)用語(yǔ),似乎最早見于大型多人在線角色扮演游戲(MMORPG)中。"Sharding" 姑且稱之為"分片"。
Sharding 不是一門新技術(shù),而是一個(gè)相對(duì)簡(jiǎn)樸的軟件理念。如您所知,MySQL 5 之后才有了數(shù)據(jù)表分區(qū)功能,那么在此之前,很多 MySQL 的潛在用戶都對(duì) MySQL 的擴(kuò)展性有所顧慮,而是否具備分區(qū)功能就成了衡量一個(gè)數(shù)據(jù)庫(kù)可擴(kuò)展性與否的一個(gè)關(guān)鍵指標(biāo)(當(dāng)然不是指標(biāo))。數(shù)據(jù)庫(kù)擴(kuò)展性是一個(gè)永恒的話題,MySQL 的推廣者經(jīng)常會(huì)被問到:如在單一數(shù)據(jù)庫(kù)上處理應(yīng)用數(shù)據(jù)捉襟見肘而需要進(jìn)行分區(qū)化之類的處理,是如何辦到的呢? 答案是:Sharding。
Sharding 不是一個(gè)某個(gè)特定數(shù)據(jù)庫(kù)軟件附屬的功能,而是在具體技術(shù)細(xì)節(jié)之上的抽象處理,是水平擴(kuò)展(Scale Out,亦或橫向擴(kuò)展、向外擴(kuò)展)的解決方案,其主要目的是為突破單節(jié)點(diǎn)數(shù)據(jù)庫(kù)服務(wù)器的 I/O 能力限制,解決數(shù)據(jù)庫(kù)擴(kuò)展性問題。
事關(guān)數(shù)據(jù)庫(kù)擴(kuò)展性
說起數(shù)據(jù)庫(kù)擴(kuò)展性,這是個(gè)非常大的話題。目前的商業(yè)數(shù)據(jù)都有自己的擴(kuò)展性解決方案,在過去相對(duì)來(lái)說比較成熟,但是隨著互聯(lián)網(wǎng)的高速發(fā)展,不可避免的會(huì)帶來(lái)一些計(jì)算模式上的演變,這樣很多主流商業(yè)系統(tǒng)也難免暴露出一些不足之處。比如 Oracle 的 RAC 是采用共享存儲(chǔ)機(jī)制,對(duì)于 I/O 密集型的應(yīng)用,瓶頸很容易落在存儲(chǔ)上,這樣的機(jī)制決定后續(xù)擴(kuò)容只能是 Scale Up(向上擴(kuò)展) 類型,對(duì)于硬件成本、開發(fā)人員的要求、維護(hù)成本都相對(duì)比較高。
Sharding 基本上是針對(duì)開源數(shù)據(jù)庫(kù)的擴(kuò)展性解決方案,很少有聽說商業(yè)數(shù)據(jù)庫(kù)進(jìn)行 Sharding 的。目前業(yè)界的趨勢(shì)基本上是擁抱 Scale Out,逐漸從 Scale Up 中解放出來(lái)。
Sharding 的應(yīng)用場(chǎng)景
任何技術(shù)都是在合適的場(chǎng)合下能發(fā)揮應(yīng)有的作用。 Sharding 也一樣。聯(lián)機(jī)游戲、IM、BSP 都是比較適合 Sharding 的應(yīng)用場(chǎng)景。其共性是抽象出來(lái)的數(shù)據(jù)對(duì)象之間的關(guān)聯(lián)數(shù)據(jù)很小。比如IM ,每個(gè)用戶如果抽象成一個(gè)數(shù)據(jù)對(duì)象,完全可以獨(dú)立存儲(chǔ)在任何一個(gè)地方,數(shù)據(jù)對(duì)象是 Share Nothing 的;再比如 Blog 服務(wù)提供商的站點(diǎn)內(nèi)容,基本為用戶生成內(nèi)容(UGC),完全可以把不同的用戶隔離到不同的存儲(chǔ)集合,而對(duì)用戶來(lái)說是透明的。
這個(gè) "Share Nothing" 是從數(shù)據(jù)庫(kù)集群中借用的概念,舉例來(lái)說,有些類型的數(shù)據(jù)粒度之間就不是 "Share Nothing" 的,比如類似交易記錄的歷史表信息,如果一條記錄中既包含賣家信息與買家信息,如果隨著時(shí)間推移,買、賣家會(huì)分別與其它用戶繼續(xù)進(jìn)行交易,這樣不可避免的兩個(gè)買賣家的信息會(huì)分布到不同的 Sharding DB 上,而這時(shí)如果針對(duì)買賣家查詢,就會(huì)跨越更多的 Sharding ,開銷就會(huì)比較大。
Sharding 并不是數(shù)據(jù)庫(kù)擴(kuò)展方案的銀彈,也有其不適合的場(chǎng)景,比如處理事務(wù)型的應(yīng)用就會(huì)非常復(fù)雜。對(duì)于跨不同DB的事務(wù),很難保證完整性,得不償失。所以,采用什么樣的 Sharding 形式,不是生搬硬套的 Sharding與數(shù)據(jù)庫(kù)分區(qū)(Partition)的區(qū)別
有的時(shí)候,Sharding 也被近似等同于水平分區(qū)(Horizontal Partitioning),網(wǎng)上很多地方也用 水平分區(qū)來(lái)指代 Sharding,但我個(gè)人認(rèn)為二者之間實(shí)際上還是有區(qū)別的。的確,Sharding 的思想是從分區(qū)的思想而來(lái),但數(shù)據(jù)庫(kù)分區(qū)基本上是數(shù)據(jù)對(duì)象級(jí)別的處理,比如表和索引的分區(qū),每個(gè)子數(shù)據(jù)集上能夠有不同的物理存儲(chǔ)屬性,還是單個(gè)數(shù)據(jù)庫(kù)范圍內(nèi)的操作,而 Sharding 是能夠跨數(shù)據(jù)庫(kù),甚至跨越物理機(jī)器的。(見對(duì)比表格)

Sharding 策略
數(shù)據(jù) Sharding 的策略與分區(qū)表的方式有很多類似的地方,有基于表、ID 范圍、數(shù)據(jù)產(chǎn)生的時(shí)間或是SOA 下理念下的基于服務(wù)等眾多方式可選擇。而與傳統(tǒng)的表分區(qū)方式不同的是,Sharding 策略和業(yè)務(wù)結(jié)合的更為緊密,成功的 Sharding 必須對(duì)自己的業(yè)務(wù)足夠熟悉,進(jìn)行眾多可行性分析的基礎(chǔ)上進(jìn)行,"業(yè)務(wù)邏輯驅(qū)動(dòng)"。
Sharding 實(shí)現(xiàn)案例分析:Digg 網(wǎng)站
作為風(fēng)頭正勁的 Web 2.0 網(wǎng)站之一的 Digg.com,雖然用戶群龐大,但網(wǎng)站數(shù)據(jù)庫(kù)數(shù)據(jù)并非海量,去年同期主數(shù)據(jù)大約只有 30GB 的樣子,現(xiàn)在應(yīng)該更大一些,但應(yīng)該不會(huì)出現(xiàn)數(shù)量級(jí)上增長(zhǎng),數(shù)據(jù)庫(kù)軟件采用 MySQL 5.x。Digg.com的 IO 壓力非常大,而且是讀集中的應(yīng)用(98%的 IO 是讀請(qǐng)求)。因?yàn)樘峁┑氖切侣勵(lì)惙?wù),這類數(shù)據(jù)有其自身特點(diǎn),最近時(shí)間段的數(shù)據(jù)往往是讀壓力的部分。
根據(jù)業(yè)務(wù)特點(diǎn),Digg.com 根據(jù)時(shí)間范圍對(duì)主要的業(yè)務(wù)數(shù)據(jù)做 Sharding,把不到 10% 的"熱"數(shù)據(jù)有效隔離開來(lái),同時(shí)對(duì)這部分?jǐn)?shù)據(jù)用以更好的硬件,提供更好的用戶體驗(yàn)。而另外 90% 的數(shù)據(jù)因用戶很少訪問,所以盡管訪問速度稍慢一點(diǎn),對(duì)用戶來(lái)說,影響也很小。通過 Sharding,Digg 達(dá)到了預(yù)期效果
現(xiàn)有的 Sharding 軟件簡(jiǎn)介
現(xiàn)在 Sharding 相關(guān)的軟件實(shí)現(xiàn)其實(shí)不少,基于數(shù)據(jù)庫(kù)層、DAO 層、不同語(yǔ)言下也都不乏案例。限于篇幅,作一下簡(jiǎn)要的介紹。
MySQL Proxy + HSCALE
一套比較有潛力的方案。其中 MySQL Proxy (http://forge.mysql.com/wiki/MySQL_Proxy) 是用 Lua 腳本實(shí)現(xiàn)的,介于客戶端與服務(wù)器端之間,扮演 Proxy 的角色,提供查詢分析、失敗接管、查詢過濾、調(diào)整等功能。目前的 0.6 版本還做不到讀、寫分離。HSCALE 則是針對(duì) MySQL Proxy 插件,也是用 Lua 實(shí)現(xiàn)的,對(duì) Sharding 過程簡(jiǎn)化了許多。需要指出的是,MySQL Proxy 與 HSCALE 各自會(huì)帶來(lái)一定的開銷,但這個(gè)開銷與集中式數(shù)據(jù)處理方式單條查詢的開銷還是要小的。
Hibernate Shards
這是 Google 技術(shù)團(tuán)隊(duì)貢獻(xiàn)的項(xiàng)目(http://www.hibernate.org/414.html),該項(xiàng)目是在對(duì) Google 財(cái)務(wù)系統(tǒng)數(shù)據(jù) Sharding 過程中誕生的。因?yàn)槭窃诳蚣軐訉?shí)現(xiàn)的,所以有其獨(dú)特的特性:標(biāo)準(zhǔn)的 Hibernate 編程模型,會(huì)用 Hibernate 就能搞定,技術(shù)成本較低;相對(duì)彈性的 Sharding 策略以及支持虛擬 Shard 等。
Spock Proxy
這也是在實(shí)際需求中產(chǎn)生的一個(gè)開源項(xiàng)目。Spock(http://www.spock.com/)是一個(gè)人員查找的 Web 2.0 網(wǎng)站。通過對(duì)自己的單一 DB 進(jìn)行有效 Sharding化 而產(chǎn)生了Spock Proxy(http://spockproxy.sourceforge.net/ ) 項(xiàng)目,Spock Proxy 算得上 MySQL Proxy 的一個(gè)分支,提供基于范圍的 Sharding 機(jī)制。Spock 是基于 Rails 的,所以Spock Proxy 也是基于 Rails 構(gòu)建,關(guān)注 RoR 的朋友不應(yīng)錯(cuò)過這個(gè)項(xiàng)目。
HiveDB
上面介紹了 RoR 的實(shí)現(xiàn),HiveDB (http://www.hivedb.org/)則是基于Java 的實(shí)現(xiàn),另外,稍有不同的是,這個(gè)項(xiàng)目背后有商業(yè)公司支持。
PL/Proxy
前面幾個(gè)都是針對(duì) MySQL 的 Sharding 方案,PL/Proxy 則是針對(duì) PostgreSQL 的,設(shè)計(jì)思想類似 Teradata 的 Hash 機(jī)制,數(shù)據(jù)存儲(chǔ)對(duì)客戶端是透明的,客戶請(qǐng)求發(fā)送到 PL/Proxy 后,由這里分布式存儲(chǔ)過程調(diào)用,統(tǒng)一分發(fā)。 PL/Proxy 的設(shè)計(jì)初衷就是在這一層充當(dāng)"數(shù)據(jù)總線"的職責(zé),所以,當(dāng)數(shù)據(jù)吞吐量支撐不住的時(shí)候,只需要增加更多的 PL/Proxy 服務(wù)器即可。大名鼎鼎的 Skype 用的就是 PL/Proxy 的解決方案。
Pyshards
http://code.google.com/p/pyshards/wiki/Pyshards 這是個(gè)基于 Python的解決方案。該工具的設(shè)計(jì)目標(biāo)還有個(gè) Re-balancing 在里面,這倒是個(gè)比較激進(jìn)的想法。目前只支持 MySQL 數(shù)據(jù)庫(kù)。
"Shard" 這個(gè)詞英文的意思是"碎片",而作為數(shù)據(jù)庫(kù)相關(guān)的技術(shù)用語(yǔ),似乎最早見于大型多人在線角色扮演游戲(MMORPG)中。"Sharding" 姑且稱之為"分片"。
Sharding 不是一門新技術(shù),而是一個(gè)相對(duì)簡(jiǎn)樸的軟件理念。如您所知,MySQL 5 之后才有了數(shù)據(jù)表分區(qū)功能,那么在此之前,很多 MySQL 的潛在用戶都對(duì) MySQL 的擴(kuò)展性有所顧慮,而是否具備分區(qū)功能就成了衡量一個(gè)數(shù)據(jù)庫(kù)可擴(kuò)展性與否的一個(gè)關(guān)鍵指標(biāo)(當(dāng)然不是指標(biāo))。數(shù)據(jù)庫(kù)擴(kuò)展性是一個(gè)永恒的話題,MySQL 的推廣者經(jīng)常會(huì)被問到:如在單一數(shù)據(jù)庫(kù)上處理應(yīng)用數(shù)據(jù)捉襟見肘而需要進(jìn)行分區(qū)化之類的處理,是如何辦到的呢? 答案是:Sharding。
Sharding 不是一個(gè)某個(gè)特定數(shù)據(jù)庫(kù)軟件附屬的功能,而是在具體技術(shù)細(xì)節(jié)之上的抽象處理,是水平擴(kuò)展(Scale Out,亦或橫向擴(kuò)展、向外擴(kuò)展)的解決方案,其主要目的是為突破單節(jié)點(diǎn)數(shù)據(jù)庫(kù)服務(wù)器的 I/O 能力限制,解決數(shù)據(jù)庫(kù)擴(kuò)展性問題。
事關(guān)數(shù)據(jù)庫(kù)擴(kuò)展性
說起數(shù)據(jù)庫(kù)擴(kuò)展性,這是個(gè)非常大的話題。目前的商業(yè)數(shù)據(jù)都有自己的擴(kuò)展性解決方案,在過去相對(duì)來(lái)說比較成熟,但是隨著互聯(lián)網(wǎng)的高速發(fā)展,不可避免的會(huì)帶來(lái)一些計(jì)算模式上的演變,這樣很多主流商業(yè)系統(tǒng)也難免暴露出一些不足之處。比如 Oracle 的 RAC 是采用共享存儲(chǔ)機(jī)制,對(duì)于 I/O 密集型的應(yīng)用,瓶頸很容易落在存儲(chǔ)上,這樣的機(jī)制決定后續(xù)擴(kuò)容只能是 Scale Up(向上擴(kuò)展) 類型,對(duì)于硬件成本、開發(fā)人員的要求、維護(hù)成本都相對(duì)比較高。
Sharding 基本上是針對(duì)開源數(shù)據(jù)庫(kù)的擴(kuò)展性解決方案,很少有聽說商業(yè)數(shù)據(jù)庫(kù)進(jìn)行 Sharding 的。目前業(yè)界的趨勢(shì)基本上是擁抱 Scale Out,逐漸從 Scale Up 中解放出來(lái)。
Sharding 的應(yīng)用場(chǎng)景
任何技術(shù)都是在合適的場(chǎng)合下能發(fā)揮應(yīng)有的作用。 Sharding 也一樣。聯(lián)機(jī)游戲、IM、BSP 都是比較適合 Sharding 的應(yīng)用場(chǎng)景。其共性是抽象出來(lái)的數(shù)據(jù)對(duì)象之間的關(guān)聯(lián)數(shù)據(jù)很小。比如IM ,每個(gè)用戶如果抽象成一個(gè)數(shù)據(jù)對(duì)象,完全可以獨(dú)立存儲(chǔ)在任何一個(gè)地方,數(shù)據(jù)對(duì)象是 Share Nothing 的;再比如 Blog 服務(wù)提供商的站點(diǎn)內(nèi)容,基本為用戶生成內(nèi)容(UGC),完全可以把不同的用戶隔離到不同的存儲(chǔ)集合,而對(duì)用戶來(lái)說是透明的。
這個(gè) "Share Nothing" 是從數(shù)據(jù)庫(kù)集群中借用的概念,舉例來(lái)說,有些類型的數(shù)據(jù)粒度之間就不是 "Share Nothing" 的,比如類似交易記錄的歷史表信息,如果一條記錄中既包含賣家信息與買家信息,如果隨著時(shí)間推移,買、賣家會(huì)分別與其它用戶繼續(xù)進(jìn)行交易,這樣不可避免的兩個(gè)買賣家的信息會(huì)分布到不同的 Sharding DB 上,而這時(shí)如果針對(duì)買賣家查詢,就會(huì)跨越更多的 Sharding ,開銷就會(huì)比較大。
Sharding 并不是數(shù)據(jù)庫(kù)擴(kuò)展方案的銀彈,也有其不適合的場(chǎng)景,比如處理事務(wù)型的應(yīng)用就會(huì)非常復(fù)雜。對(duì)于跨不同DB的事務(wù),很難保證完整性,得不償失。所以,采用什么樣的 Sharding 形式,不是生搬硬套的 Sharding與數(shù)據(jù)庫(kù)分區(qū)(Partition)的區(qū)別
有的時(shí)候,Sharding 也被近似等同于水平分區(qū)(Horizontal Partitioning),網(wǎng)上很多地方也用 水平分區(qū)來(lái)指代 Sharding,但我個(gè)人認(rèn)為二者之間實(shí)際上還是有區(qū)別的。的確,Sharding 的思想是從分區(qū)的思想而來(lái),但數(shù)據(jù)庫(kù)分區(qū)基本上是數(shù)據(jù)對(duì)象級(jí)別的處理,比如表和索引的分區(qū),每個(gè)子數(shù)據(jù)集上能夠有不同的物理存儲(chǔ)屬性,還是單個(gè)數(shù)據(jù)庫(kù)范圍內(nèi)的操作,而 Sharding 是能夠跨數(shù)據(jù)庫(kù),甚至跨越物理機(jī)器的。(見對(duì)比表格)

Sharding 策略
數(shù)據(jù) Sharding 的策略與分區(qū)表的方式有很多類似的地方,有基于表、ID 范圍、數(shù)據(jù)產(chǎn)生的時(shí)間或是SOA 下理念下的基于服務(wù)等眾多方式可選擇。而與傳統(tǒng)的表分區(qū)方式不同的是,Sharding 策略和業(yè)務(wù)結(jié)合的更為緊密,成功的 Sharding 必須對(duì)自己的業(yè)務(wù)足夠熟悉,進(jìn)行眾多可行性分析的基礎(chǔ)上進(jìn)行,"業(yè)務(wù)邏輯驅(qū)動(dòng)"。
Sharding 實(shí)現(xiàn)案例分析:Digg 網(wǎng)站
作為風(fēng)頭正勁的 Web 2.0 網(wǎng)站之一的 Digg.com,雖然用戶群龐大,但網(wǎng)站數(shù)據(jù)庫(kù)數(shù)據(jù)并非海量,去年同期主數(shù)據(jù)大約只有 30GB 的樣子,現(xiàn)在應(yīng)該更大一些,但應(yīng)該不會(huì)出現(xiàn)數(shù)量級(jí)上增長(zhǎng),數(shù)據(jù)庫(kù)軟件采用 MySQL 5.x。Digg.com的 IO 壓力非常大,而且是讀集中的應(yīng)用(98%的 IO 是讀請(qǐng)求)。因?yàn)樘峁┑氖切侣勵(lì)惙?wù),這類數(shù)據(jù)有其自身特點(diǎn),最近時(shí)間段的數(shù)據(jù)往往是讀壓力的部分。
根據(jù)業(yè)務(wù)特點(diǎn),Digg.com 根據(jù)時(shí)間范圍對(duì)主要的業(yè)務(wù)數(shù)據(jù)做 Sharding,把不到 10% 的"熱"數(shù)據(jù)有效隔離開來(lái),同時(shí)對(duì)這部分?jǐn)?shù)據(jù)用以更好的硬件,提供更好的用戶體驗(yàn)。而另外 90% 的數(shù)據(jù)因用戶很少訪問,所以盡管訪問速度稍慢一點(diǎn),對(duì)用戶來(lái)說,影響也很小。通過 Sharding,Digg 達(dá)到了預(yù)期效果
現(xiàn)有的 Sharding 軟件簡(jiǎn)介
現(xiàn)在 Sharding 相關(guān)的軟件實(shí)現(xiàn)其實(shí)不少,基于數(shù)據(jù)庫(kù)層、DAO 層、不同語(yǔ)言下也都不乏案例。限于篇幅,作一下簡(jiǎn)要的介紹。
MySQL Proxy + HSCALE
一套比較有潛力的方案。其中 MySQL Proxy (http://forge.mysql.com/wiki/MySQL_Proxy) 是用 Lua 腳本實(shí)現(xiàn)的,介于客戶端與服務(wù)器端之間,扮演 Proxy 的角色,提供查詢分析、失敗接管、查詢過濾、調(diào)整等功能。目前的 0.6 版本還做不到讀、寫分離。HSCALE 則是針對(duì) MySQL Proxy 插件,也是用 Lua 實(shí)現(xiàn)的,對(duì) Sharding 過程簡(jiǎn)化了許多。需要指出的是,MySQL Proxy 與 HSCALE 各自會(huì)帶來(lái)一定的開銷,但這個(gè)開銷與集中式數(shù)據(jù)處理方式單條查詢的開銷還是要小的。
Hibernate Shards
這是 Google 技術(shù)團(tuán)隊(duì)貢獻(xiàn)的項(xiàng)目(http://www.hibernate.org/414.html),該項(xiàng)目是在對(duì) Google 財(cái)務(wù)系統(tǒng)數(shù)據(jù) Sharding 過程中誕生的。因?yàn)槭窃诳蚣軐訉?shí)現(xiàn)的,所以有其獨(dú)特的特性:標(biāo)準(zhǔn)的 Hibernate 編程模型,會(huì)用 Hibernate 就能搞定,技術(shù)成本較低;相對(duì)彈性的 Sharding 策略以及支持虛擬 Shard 等。
Spock Proxy
這也是在實(shí)際需求中產(chǎn)生的一個(gè)開源項(xiàng)目。Spock(http://www.spock.com/)是一個(gè)人員查找的 Web 2.0 網(wǎng)站。通過對(duì)自己的單一 DB 進(jìn)行有效 Sharding化 而產(chǎn)生了Spock Proxy(http://spockproxy.sourceforge.net/ ) 項(xiàng)目,Spock Proxy 算得上 MySQL Proxy 的一個(gè)分支,提供基于范圍的 Sharding 機(jī)制。Spock 是基于 Rails 的,所以Spock Proxy 也是基于 Rails 構(gòu)建,關(guān)注 RoR 的朋友不應(yīng)錯(cuò)過這個(gè)項(xiàng)目。
HiveDB
上面介紹了 RoR 的實(shí)現(xiàn),HiveDB (http://www.hivedb.org/)則是基于Java 的實(shí)現(xiàn),另外,稍有不同的是,這個(gè)項(xiàng)目背后有商業(yè)公司支持。
PL/Proxy
前面幾個(gè)都是針對(duì) MySQL 的 Sharding 方案,PL/Proxy 則是針對(duì) PostgreSQL 的,設(shè)計(jì)思想類似 Teradata 的 Hash 機(jī)制,數(shù)據(jù)存儲(chǔ)對(duì)客戶端是透明的,客戶請(qǐng)求發(fā)送到 PL/Proxy 后,由這里分布式存儲(chǔ)過程調(diào)用,統(tǒng)一分發(fā)。 PL/Proxy 的設(shè)計(jì)初衷就是在這一層充當(dāng)"數(shù)據(jù)總線"的職責(zé),所以,當(dāng)數(shù)據(jù)吞吐量支撐不住的時(shí)候,只需要增加更多的 PL/Proxy 服務(wù)器即可。大名鼎鼎的 Skype 用的就是 PL/Proxy 的解決方案。
Pyshards
http://code.google.com/p/pyshards/wiki/Pyshards 這是個(gè)基于 Python的解決方案。該工具的設(shè)計(jì)目標(biāo)還有個(gè) Re-balancing 在里面,這倒是個(gè)比較激進(jìn)的想法。目前只支持 MySQL 數(shù)據(jù)庫(kù)。