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

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

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