MySQL Sharding詳解

轉自(http://blog.sina.com.cn/s/blog_821512b50101hyc1.html)

MySQL Sharding詳解

   

一 背景html

咱們知道,當數據庫中的數據量愈來愈大時,不管是讀仍是寫,壓力都會變得愈來愈大。採用MySQL Replication多master多slave方案,在上層作負載均衡,雖然可以必定程度上緩解壓力。可是當一張表中的數據變得很是龐大時,壓力仍是 很是大的。試想,若是一張表中的數據量達到了千萬甚至上億級別的時候,無論是建索引,優化緩存等,都會面臨巨大的性能壓力。前端

二 定義mysql

數據sharding,也稱做數據切分,或分區。是指經過某種條件,把同一個數據庫中的數據分散到多個數據庫或多臺機器上,以減少單臺機器壓力。git

三 分類github

數據分區根據切分規則,能夠分爲兩類:sql

1、垂直切分數據庫

數據的垂直切分,也能夠稱之爲縱向切分。將數據庫想象成爲由不少個一大塊一大塊的「數據塊」(表)組成,咱們垂直的將這些「數據塊」切開,而後將他們分散 到多臺數據庫主機上面。這樣的切分方法就是一個垂直(縱向)的數據切分。以表爲單位,把不一樣的表分散到不一樣的數據庫或主機上。規則簡單,實施方便,適合業 務之間耦合度低的系統。編程

Sharding詳解" title="MySQL Sharding詳解" height="373" width="553">後端

垂直切分的優勢緩存

(1)數據庫的拆分簡單明瞭,拆分規則明確;

(2)應用程序模塊清晰明確,整合容易;

(3)數據維護方便易行,容易定位;

垂直切分的缺點

(1)部分表關聯沒法在數據庫級別完成,須要在程序中完成;

(2)對於訪問極其頻繁且數據量超大的表仍然存在性能平靜,不必定能知足要求;

(3)事務處理相對更爲複雜;

(4) 切分達到必定程度以後,擴展性會遇到限制;

(5)過讀切分可能會帶來系統過渡複雜而難以維護。

2、水平切分

通常來講,簡單的水平切分主要是將某個訪問極其平凡的表再按照某個字段的某種規則來分散到多個表之中,每一個表中包含一部分數據。以行爲單位,將同一個表中的數據按照某種條件拆分到不一樣的數據庫或主機上。相對複雜,適合單表巨大的系統。

Sharding詳解" title="MySQL Sharding詳解" height="372" width="553">

水平切分的優勢

(1)表關聯基本可以在數據庫端所有完成;

(2)不會存在某些超大型數據量和高負載的表遇到瓶頸的問題;

(3)應用程序端總體架構改動相對較少;

(4)事務處理相對簡單;

(5)只要切分規則可以定義好,基本上較難遇到擴展性限制;

水平切分的缺點

(1)切分規則相對更爲複雜,很難抽象出一個可以知足整個數據庫的切分規則;

(2)後期數據的維護難度有所增長,人爲手工定位數據更困難;

(3)應用系統各模塊耦合度較高,可能會對後面數據的遷移拆分形成必定的困難。

3、聯合切分

實際的應用場景中,除了那些負載並非太大,業務邏輯也相對較簡單的系統能夠經過上面兩種切分方法之一來解決擴展性問題以外,恐怕其餘大部分業務邏輯稍微 複雜一點,系統負載大一些的系統,都沒法經過上面任何一種數據的切分方法來實現較好的擴展性,而須要將上述兩種切分方法結合使用,不一樣的場景使用不一樣的切 分方法。

Sharding詳解" title="MySQL Sharding詳解" height="480" width="342">

聯合切分的優勢

(1)能夠充分利用垂直切分和水平切分各自的優點而避免各自的缺陷;

(2)讓系統擴展性獲得最大化提高;

聯合切分的缺點

(1)數據庫系統架構比較複雜,維護難度更大;

(2)應用程序架構也相對更復雜;

四 實現方案

如今 Sharding 相關的軟件實現其實很多,基於數據庫層、DAO 層、不一樣語言下也都不乏案例。限於篇幅,此處只做一下簡要的介紹。

1、 Mysql Proxy + HASCALE

一套比較有潛力的方案。其中MySQL Proxy  是用 Lua 腳本實現的,介於客戶端與服務器端之間,扮演 Proxy 的角色,提供查詢分析、失敗接管、查詢過濾、調整等功能。目前的 0.6 版本還作不到讀、寫分離。HSCALE 則是針對 MySQL Proxy 插件,也是用 Lua 實現的,對 Sharding 過程簡化了許多。須要指出的是,MySQL Proxy 與 HSCALE 各自會帶來必定的開銷,但這個開銷與集中式數據處理方式單條查詢的開銷仍是要小的。

MySQLProxy是MySQL官方提供的一個數據庫代理層產品,和MySQLServer同樣,一樣是一個基於GPL開源協議的開源產品。可用來監視、分析或者傳輸他們之間的通信信息。他的靈活性容許你最大限度的使用它,目前具有的功能主要有鏈接路由,Query分析,Query過濾和修改,負載均衡,以及基本的HA機制等。

實際上,MySQLProxy自己並不具備上述全部的這些功能,而是提供了實現上述功能的基礎。要實現這些功能,還須要經過咱們自行編寫LUA腳原本實現。

MySQLProxy其實是在客戶端請求與MySQLServer之間創建了一個鏈接池。全部客戶端請求都是發向MySQLProxy,而後經由MySQLProxy進行相應的分析,判斷出是讀操做仍是寫操做,分發至對應的MySQLServer上。對於多節點Slave集羣,也能夠起作到負載均衡的效果。如下是MySQLProxy的基本架構圖:

 

Sharding詳解" title="MySQL Sharding詳解" height="480" width="420">

經過上面的架構簡圖,咱們能夠很清晰的看出MySQLProxy在實際應用中所處的位置,以及能作的基本事情。關於MySQLProxy更爲詳細的實施細則在MySQL官方文檔中有很是詳細的介紹和示例,感興趣的讀者朋友能夠直接從MySQL官方網站免費下載或者在線閱讀,我這裏就不累述浪費紙張了。

http://forge.mysql.com/wiki/MySQL_Proxy

2、 Hibernate Shards

這是 Google 技術團隊貢獻的項目(http://www.hibernate.org/414.html),該項目是在對Google 財務系統數據 Sharding 過程當中誕生的。由於是在框架層實現的,因此有其獨特的特性:標準的 Hibernate 編程模型,會用 Hibernate 就能搞定,技術成本較低;相對彈性的 Sharding 策略以及支持虛擬 Shard 等。

3、 Spock Proxy

這也是在實際需求中產生的一個開源項目,基於Mysql Proxy擴展。Spock(http://www.spock.com/)是一我的員查找的 Web 2.0 網站。經過對本身的單一 DB 進行有效 Sharding化 而產生了Spock Proxy(http://spockproxy.sourceforge.net/ ) 項目,Spock Proxy 算得上 MySQL Proxy 的一個分支,提供基於範圍的 Sharding 機制。Spock 是基於 Rails 的,因此Spock Proxy 也是基於 Rails 構建,關注 ROR 的朋友不該錯過這個項目。

http://spockproxy.sourceforge.net/

4、 Amoeba for MySQL

Amoeba是一個基於Java開發的,專一於解決分佈式數據庫數據源整合Proxy程序的開源框架,基於GPL3開源協議。目前,Amoeba已經具備Query路由,Query過濾,讀寫分離,負載均衡以及HA機制等相關內容。

Amoeba 主要解決的如下幾個問題:

(1)數據切分後複雜數據源整合;

(2)提供數據切分規則並下降數據切分規則給數據庫帶來的影響;

(3)下降數據庫與客戶端的鏈接數;

(4)讀寫分離路由。

咱們能夠看出,Amoeba所作的事情,正好就是咱們經過數據切分來提高數據庫的擴展性所須要的。

Amoeba並非一個代理層的Proxy程序,而是一個開發數據庫代理層Proxy程序的開發框架,目前基於Amoeba所開發的Proxy程序有AmoebaForMySQL和AmoebaForAladin兩個。

AmoebaForMySQL主要是專門針對MySQL數據庫的解決方案,前端應用程序請求的協議以及後端鏈接的數據源數據庫都必須是MySQL。對於客戶端的任何應用程序來講,AmoebaForMySQL和一個MySQL數據庫沒有什麼區別,任何使用MySQL協議的客戶端請求,均可以被AmoebaForMySQL解析並進行相應的處理。下如能夠告訴咱們AmoebaForMySQL的架構信息(出自Amoeba開發者博客):

 

Sharding詳解" title="MySQL Sharding詳解" height="480" width="384">

AmoebaForAladin則是一個適用更爲普遍,功能更爲強大的Proxy程序。他能夠同時鏈接不一樣數據庫的數據源爲前端應用程序提供服務,可是僅僅接受符合MySQL協議的客戶端應用程序請求。也就是說,只要前端應用程序經過MySQL協議鏈接上來以後,AmoebaForAladin會自動分析Query語句,根據Query語句中所請求的數據來自動識別出該所Query的數據源是在什麼類型數據庫的哪個物理主機上面。下圖展現了AmoebaForAladin的架構細節(出自Amoeba開發者博客):

 

Sharding詳解" title="MySQL Sharding詳解" height="480" width="384">

咋一看,二者好像徹底同樣嘛。細看以後,纔會發現二者主要的區別僅在於經過MySQLProtocalAdapter處理以後,根據分析結果判斷出數據源數據庫,而後選擇特定的JDBC驅動和相應協議鏈接後端數據庫。

其實經過上面兩個架構圖你們可能也已經發現了Amoeba的特色了,他僅僅只是一個開發框架,咱們除了選擇他已經提供的ForMySQL和ForAladin這兩款產品以外,還能夠基於自身的需求進行相應的二次開發,獲得更適應咱們本身應用特色的Proxy程序。

當對於使用MySQL數據庫來講,不管是AmoebaForMySQL仍是AmoebaForAladin均可以很好的使用。固然,考慮到任何一個系統越是複雜,其性能確定就會有必定的損失,維護成本天然也會相對更高一些。因此,對於僅僅須要使用MySQL數據庫的時候,我仍是建議使用AmoebaForMySQL。

AmoebaForMySQL的使用很是簡單,全部的配置文件都是標準的XML文件,總共有四個配置文件。分別爲:

(1)amoeba.xml:主配置文件,配置全部數據源以及Amoeba自身的參數設置;

(2)rule.xml:配置全部Query路由規則的信息;

(3)functionMap.xml:配置用於解析Query中的函數所對應的Java實現類;

(4)rullFunctionMap.xml:配置路由規則中須要使用到的特定函數的實現類;

若是您的規則不是太複雜,基本上僅須要使用到上面四個配置文件中的前面兩個就可完成全部工做。Proxy程序經常使用的功能如讀寫分離,負載均衡等配置都在amoeba.xml中進行。此外,Amoeba已經支持了實現數據的垂直切分和水平切分的自動路由,路由規則能夠在rule.xml進行設置。

目前Amoeba少有欠缺的主要就是其在線管理功能以及對事務的支持了,曾經在與相關開發者的溝經過程中提出過相關的建議,但願可以提供一個能夠進行在線維護管理的命令行管理工具,方便在線維護使用,獲得的反饋是管理專門的管理模塊已經歸入開發日程了。另外在事務支持方面暫時仍是Amoeba沒法作到的,即便客戶端應用在提交給Amoeba的請求是包含事務信息的,Amoeba也會忽略事務相關信息。固然,在通過不斷完善以後,我相信事務支持確定是Amoeba重點考慮增長的feature。

關於Amoeba更爲詳細的使用方法讀者朋友能夠經過Amoeba開發者博客(http://amoeba.sf.net)上面提供的使用手冊獲取,這裏就再也不細述了。

案例(http://pengranxiang.iteye.com/blog/1145342)

操做文檔(http://docs.hexnova.com/amoeba/chap-getting-started.html)

5、 HiveDB

和前面的MySQLProxy以及Amoeba同樣,HiveDB一樣是一個基於Java針對MySQL數據庫的提供數據切分及整合的開源框架,只是目前的HiveDB僅僅支持數據的水平切分。主要解決大數據量下數據庫的擴展性及數據的高性能訪問問題,同時支持數據的冗餘及基本的HA機制。

HiveDB的實現機制與MySQLProxy和Amoeba有必定的差別,他並非藉助MySQL的Replication功能來實現數據的冗餘,而是自行實現了數據冗餘機制,而其底層主要是基於HibernateShards來實現的數據切分工做。

在HiveDB中,經過用戶自定義的各類Partitionkeys(其實就是制定數據切分規則),將數據分散到多個MySQLServer中。在訪問的時候,在運行Query請求的時候,會自動分析過濾條件,並行從多個MySQLServer中讀取數據,併合並結果集返回給客戶端應用程序。

單純從功能方面來說,HiveDB可能並不如MySQLProxy和Amoeba那樣強大,可是其數據切分的思路與前面兩者並沒有本質差別。此外,HiveDB並不只僅只是一個開源愛好者所共享的內容,而是存在商業公司支持的開源項目。

下面是HiveDB官方網站上面一章圖片,描述了HiveDB如何來組織數據的基本信息,雖然不能詳細的表現出太多架構方面的信息,可是也基本能夠展現出其在數據切分方面獨特的一面了。

 

Sharding詳解" title="MySQL Sharding詳解" height="471" width="553">

http://www.hivedb.org/

6、 DataFabric

application-level sharding

master/slave replication

https://github.com/bpot/data_fabric

7、PL/Proxy

前面幾個都是針對MySQL 的 Sharding 方案,PL/Proxy 則是針對 PostgreSQL 的,設計思想相似 Teradata 的 Hash 機制,數據存儲對客戶端是透明的,客戶請求發送到 PL/Proxy 後,由這裏分佈式存儲過程調用,統一分發。 PL/Proxy 的設計初衷就是在這一層充當」數據總線」的職責,因此,當數據吞吐量支撐不住的時候,只須要增長更多的 PL/Proxy 服務器便可。大名鼎鼎的 Skype 用的就是 PL/Proxy 的解決方案。

8、Pyshards

這是個基於Python的解決方案。該工具的設計目標還有個 Re-balancing 在裏面,這卻是個比較激進的想法。目前只支持 MySQL 數據庫。

http://code.google.com/p/pyshards/wiki/Pyshards

9、其餘實現數據切分及整合的解決方案

除了上面介紹的幾個數據切分及整合的總體解決方案以外,還存在不少其餘一樣提供了數據切分與整合的解決方案。如基於MySQLProxy的基礎上作了進一步擴展的HSCALE,經過Rails構建的SpockProxy,以及基於Pathon的Pyshards等等。

無論你們選擇使用哪種解決方案,整體設計思路基本上都不該該會有任何變化,那就是經過數據的垂直和水平切分,加強數據庫的總體服務能力,讓應用系統的總體擴展能力盡量的提高,擴展方式儘量的便捷。

只要咱們經過中間層Proxy應用程序較好的解決了數據切分和數據源整合問題,那麼數據庫的線性擴展能力將很容易作到像咱們的應用程序同樣方便,只須要經過添加廉價的PCServer服務器,便可線性增長數據庫集羣的總體服務能力,讓數據庫再也不輕易成爲應用系統的性能瓶頸。

五 注意事項

下面咱們所說的分區,主要是指水平分區。

一、在實施分區前,咱們能夠查看所安裝版本的mysql是否支持分區:

mysql> show variables like "%partition%";

若是支持則會顯示:

        +-------------------+-------+

        | Variable_name     | Value |

        +-------------------+-------+

        | have_partitioning | YES   |

        +-------------------+-------+

二、分區適用於一個表的全部數據和索引,不能只對數據分區而不對索引分區,反之亦然,同時也不能只對表的一部分進行分區。

三、分區類型

(1)RANGE 分區:基於屬於一個給定連續區間的列值,把多行分配給分區。

(2)LIST 分區:相似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。

(3)HASH分區:基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算(新浪微博採用的方案)。

(4)KEY 分區:相似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL 服務器提供其自身的哈希函數。必須有一列或多列包含整數值。

不管使用何種類型的分區,分區老是在建立時就自動的順序編號,且從0開始記錄。當有一新行插入到一個分區表中時,就是使用這些分區編號來識別正確的分區。

四、MySQL提供了許多修改分區表的方式。添加、刪除、從新定義、合併或拆分已經存在的分區是可能的。全部這些操做均可以經過使用ALTER TABLE 命令的分區擴展來實現。

五、能夠對已經存在的表進行分區,直接使用alter table命令便可。

六 數據切分與整合可能存在的問題

這裏,你們應該對數據切分與整合的實施有了必定的認識了,或許不少讀者朋友都已經根據各類解決方案各自特性的優劣基本選定了適合於本身應用場景的方案,後面的工做主要就是實施準備了。

在實施數據切分方案以前,有些可能存在的問題咱們仍是須要作一些分析的。通常來講,咱們可能遇到的問題主要會有如下幾點:

一、引入分佈式事務的問題

一旦數據進行切分被分別存放在多個MySQLServer中以後,無論咱們的切分規則設計的多麼的完美(實際上並不存在完美的切分規則),均可能形成以前的某些事務所涉及到的數據已經不在同一個MySQLServer中了。

在這樣的場景下,若是咱們的應用程序仍然按照老的解決方案,那麼勢必須要引入分佈式事務來解決。而在MySQL各個版本中,只有從MySQL5.0開始之後的各個版本纔開始對分佈式事務提供支持,並且目前僅有Innodb提供分佈式事務支持。不只如此,即便咱們恰好使用了支持分佈式事務的MySQL版本,同時也是使用的Innodb存儲引擎,分佈式事務自己對於系統資源的消耗就是很大的,性能自己也並非過高。並且引入分佈式事務自己在異常處理方面就會帶來較多比較難控制的因素。

怎麼辦?其實咱們能夠能夠經過一個變通的方法來解決這種問題,首先須要考慮的一件事情就是:是否數據庫是惟一一個可以解決事務的地方呢?其實並非這樣 的,咱們徹底能夠結合數據庫以及應用程序二者來共同解決。各個數據庫解決本身身上的事務,而後經過應用程序來控制多個數據庫上面的事務。

也就是說,只要咱們願意,徹底能夠將一個跨多個數據庫的分佈式事務分拆成多個僅處於單個數據庫上面的小事務,並經過應用程序來總控各個小事務。固然,這樣做的要求就是咱們的俄應用程序必需要有足夠的健壯性,固然也會給應用程序帶來一些技術難度。

二、跨節點Join的問題

上面介紹了可能引入分佈式事務的問題,如今咱們再看看須要跨節點Join的問題。數據切分以後,可能會形成有些老的Join語句沒法繼續使用,由於Join使用的數據源可能被切分到多個MySQLServer中了。

怎麼辦?這個問題從MySQL數據庫角度來看,若是非得在數據庫端來直接解決的話,恐怕只能經過MySQL一種特殊的存儲引擎Federated來解決了。Federated存儲引擎是MySQL解決相似於Oracle的DBLink之類問題的解決方案。和OracleDBLink的主要區別在於Federated會保存一份遠端表結構的定義信息在本地。咋一看,Federated確實是解決跨節點Join很是好的解決方案。可是咱們還應該清楚一點,那就彷佛若是遠端的表結構發生了變動,本地的表定義信息是不會跟着發生相應變化的。若是在更新遠端表結構的時候並無更新本地的Federated表定義信息,就極可能形成Query運行出錯,沒法獲得正確的結果。

對待這類問題,我仍是推薦經過應用程序來進行處理,先在驅動表所在的MySQLServer中取出相應的驅動結果集,而後根據驅動結果集再到被驅動表所在的MySQLServer中取出相應的數據。可能不少讀者朋友會認爲這樣作對性能會產生必定的影響,是的,確實是會對性能有必定的負面影響,可是除了此法,基本上沒有太多其餘更好的解決辦法了。並且,因爲數據庫經過較好的擴展以後,每臺MySQLServer的負載就能夠獲得較好的控制,單純針對單條Query來講,其響應時間可能比不切分以前要提升一些,因此性能方面所帶來的負面影響也並非太大。更況且,相似於這種須要跨節點Join的需求也並非太多,相對於整體性能而言,可能也只是很小一部分而已。因此爲了總體性能的考慮,偶爾犧牲那麼一點點,實際上是值得的,畢竟系統優化自己就是存在不少取捨和平衡的過程。

三、跨節點合併排序分頁問題

一旦進行了數據的水平切分以後,可能就並不只僅只有跨節點Join沒法正常運行,有些排序分頁的Query語句的數據源可能也會被切分到多個節點,這樣形成的直接後果就是這些排序分頁Query沒法繼續正常運行。其實這和跨節點Join是一個道理,數據源存在於多個節點上,要經過一個Query來解決,就和跨節點Join是同樣的操做。一樣Federated也能夠部分解決,固然存在的風險也同樣。

仍是一樣的問題,怎麼辦?我一樣仍然繼續建議經過應用程序來解決。

如何解決?解決的思路大致上和跨節點Join的解決相似,可是有一點和跨節點Join不太同樣,Join不少時候都有一個驅動與被驅動的關係,因此Join本 身涉及到的多個表之間的數據讀取通常都會存在一個順序關係。可是排序分頁就不太同樣了,排序分頁的數據源基本上能夠說是一個表(或者一個結果集),自己並 不存在一個順序關係,因此在從多個數據源取數據的過程是徹底能夠並行的。這樣,排序分頁數據的取數效率咱們能夠作的比跨庫Join更高,因此帶來的性能損失相對的要更小,在有些狀況下可能比在原來未進行數據切分的數據庫中效率更高了。固然,不管是跨節點Join仍是跨節點排序分頁,都會使咱們的應用服務器消耗更多的資源,尤爲是內存資源,由於咱們在讀取訪問以及合併結果集的這個過程須要比原來處理更多的數據。

分析到這裏,可能不少讀者朋友會發現,上面全部的這些問題,我給出的建議基本上都是經過應用程序來解決。你們可能內心開始犯嘀咕了,是否是由於我是DBA,因此就不少事情都扔給應用架構師和開發人員了?

其實徹底不是這樣,首先應用程序因爲其特殊性,能夠很是容易作到很好的擴展性,可是數據庫就不同,必須藉助不少其餘的方式才能作到擴展,並且在這個擴展 過程當中,很難避免帶來有些原來在集中式數據庫中能夠解決但被切分開成一個數據庫集羣以後就成爲一個難題的狀況。要想讓系統總體獲得最大限度的擴展,咱們只 能讓應用程序作更多的事情,來解決數據庫集羣沒法較好解決的問題。

七 MySQL基於Amoeba的水平和垂直分片示例

 詳細的配置描述請參考:http://pengranxiang.iteye.com/blog/1145342

相關文章
相關標籤/搜索