MySQL垂直和水平切分-轉載整理

chenfeng發表於2016-01-30
replication的限制:一旦資料庫過於龐大,尤其是當寫入過於頻繁,很難由一臺主機支撐的時候,我們還是會面臨到擴充套件瓶頸。資料切分(sharding):透過某種特定的條件,將我們存放在同一個資料庫中的資料分散存放到多個資料庫(主機)上面,以達到分散單臺裝置負載的效果。。資料的切分同時還可以提高系統的總體可用性,因為單臺裝置Crash之後,只有總體資料的某部分不可用,而不是所有的資料。


資料的切分(Sharding)模式

一種是按照不同的表(或者Schema)來切分到不同的資料庫(主機)之上,這種切可以稱之為資料的垂直(縱向)切分;另外一種則是根據表中的資料的邏輯關係,將同一個表中的資料按照某種條件拆分到多臺資料庫(主機)上面,這種切分稱之為資料的水平(橫向)切分。


垂直切分:

一個架構設計較好的應用系統,其總體功能肯定是由很多個功能模組所組成的,而每一個功能模組所需要的資料對應到資料庫中就是一個或者多個表。而在架構設計中,各個功能模組相互之間的互動點越統一越少,系統的耦合度就越低,系統各個模組的維護性以及擴充套件性也就越好。這樣的系統,實現資料的垂直切分也就越容易。


一般來說,如果是一個負載相對不是很大的系統,而且表關聯又非常的頻繁,那可能資料庫讓步,將幾個相關模組合併在一起減少應用程式的工作的方案可以減少較多的工作量,這是一個可行的方案。一個垂直拆分的例子:

1.使用者模組表:user,user_profile,user_group,user_photo_album
2.群組討論表:groups,group_message,group_message_content,top_message
3.相簿相關表:photo,photo_album,photo_album_relation,photo_comment
4.事件資訊表:event


群組討論模組和使用者模組之間主要存在透過使用者或者是群組關係來進行關聯。一般關聯的時候都會是透過使用者的id或者nick_name以及group的id來進行關聯,透過模組之間的介面實現不會帶來太多麻煩;
相簿模組僅僅與使用者模組存在透過使用者的關聯。這兩個模組之間的關聯基本就有透過使用者id關聯的內容,簡單清晰,介面明確;
事件模組與各個模組可能都有關聯,但是都只關注其各個模組中物件的ID資訊,同樣可以做到很容易分拆。


垂直切分的優點

資料庫的拆分簡單明瞭,拆分規則明確;
應用程式模組清晰明確,整合容易;
資料維護方便易行,容易定位;


垂直切分的缺點

部分表關聯無法在資料庫級別完成,需要在程式中完成;
對於訪問極其頻繁且資料量超大的表仍然存在效能瓶頸,不一定能滿足要求;
事務處理相對更為複雜;
切分達到一定程度之後,擴充套件性會遇到限制;
過讀切分可能會帶來系統過渡複雜而難以維護。


水平切分

將某個訪問極其頻繁的表再按照某個欄位的某種規則來分散到多個表之中,每個表中包含一部分資料。

對於上面的例子:所有資料都是和使用者關聯的,那麼我們就可以根據使用者來進行水平拆分,將不同使用者的資料切分到不同的資料庫中。

現在網際網路非常火爆的Web2.0型別的網站,基本上大部分資料都能夠透過會員使用者資訊關聯上,可能很多核心表都非常適合透過會員ID來進行資料的水平切分。而像論壇社群討論系統,就更容易切分了,非常容易按照論壇編號來進行資料的水平切分。切分之後基本上不會出現各個庫之間的互動。


水平切分的優點

表關聯基本能夠在資料庫端全部完成;
不會存在某些超大型資料量和高負載的表遇到瓶頸的問題;
應用程式端整體架構改動相對較少;
事務處理相對簡單;
只要切分規則能夠定義好,基本上較難遇到擴充套件性限制;


水平切分的缺點

切分規則相對更為複雜,很難抽象出一個能夠滿足整個資料庫的切分規則;
後期資料的維護難度有所增加,人為手工定位資料更困難;
應用系統各模組耦合度較高,可能會對後面資料的遷移拆分造成一定的困難。


兩種切分結合用:

一般來說,我們資料庫中的所有表很難透過某一個(或少數幾個)欄位全部關聯起來,所以很難簡單的僅僅透過資料的水平切分來解決所有問題。而垂直切分也只能解決部分問題,對於那些負載非常高的系統,即使僅僅只是單個表都無法透過單臺資料庫主機來承擔其負載。我們必須結合“垂直”和“水平”兩種切分方式同時使用


每一個應用系統的負載都是一步一步增長上來的,在開始遇到效能瓶頸的時候,大多數架構師和DBA都會選擇先進行資料的垂直拆分,因為這樣的成本最先,最符合這個時期所追求的最大投入產出比。然而,隨著業務的不斷擴張,系統負載的持續增長,在系統穩定一段時期之後,經過了垂直拆分之後的資料庫叢集可能又再一次不堪重負,遇到了效能瓶頸。


如果我們再一次像最開始那樣繼續細分模組,進行資料的垂直切分,那我們可能在不久的將來,又會遇到現在所面對的同樣的問題。而且隨著模組的不斷的細化,應用系統的架構也會越來越複雜,整個系統很可能會出現失控的局面。


這時候我們就必須要透過資料的水平切分的優勢,來解決這裡所遇到的問題。而且,我們完全不必要在使用資料水平切分的時候,推倒之前進行資料垂直切分的成果,而是在其基礎上利用水平切分的優勢來避開垂直切分的弊端,解決系統複雜性不斷擴大的問題。而水平拆分的弊端(規則難以統一)也已經被之前的垂直切分解決掉了,讓水平拆分可以進行的得心應手。


示例資料庫:


假設在最開始,我們進行了資料的垂直切分,然而隨著業務的不斷增長,資料庫系統遇到了瓶頸,我們選擇重構資料庫叢集的架構。如何重構?考慮到之前已經做好了資料的垂直切分,而且模組結構清晰明確。而業務增長的勢頭越來越猛,即使現在進一步再次拆分模組,也堅持不了太久。


==>選擇了在垂直切分的基礎上再進行水平拆分。


==>在經歷過垂直拆分後的各個資料庫叢集中的每一個都只有一個功能模組,而每個功能模組中的所有表基本上都會與某個欄位進行關聯。如使用者模組全部都可以透過使用者ID進行切分,群組討論模組則都透過群組ID來切分,相簿模組則根據相簿ID來進切分,最後的事件通知資訊表考慮到資料的時限性(僅僅只會訪問最近某個事件段的資訊),則考慮按時間來切分。


資料切分以及整合方案.


資料庫中的資料在經過垂直和(或)水平切分被存放在不同的資料庫主機之後,應用系統面臨的最大問題就是如何來讓這些資料來源得到較好的整合,其中存在兩種解決思路:


在每個應用程式模組中配置管理自己需要的一個(或者多個)資料來源,直接訪問各個資料庫,在模組內完成資料的整合;
透過中間代理層來統一管理所有的資料來源,後端資料庫叢集對前端應用程式透明;


第二種方案,雖然短期內需要付出的成本可能會相對更大一些,但是對整個系統的擴充套件性來說,是非常有幫助的。針對第二種方案,可以選擇的方法和思路有:


1.利用MySQLProxy 實現資料切分及整合.


可用來監視、分析或者傳輸他們之間的通訊資訊。他的靈活性允許你最大限度的使用它,目前具備的功能主要有連線路由,Query分析,Query過濾和修改,負載均衡,以及基本的HA機制等。MySQLProxy 本身並不具有上述所有的這些功能,而是提供了實現上述功能的基礎。要實現這些功能,還需要透過我們自行編寫LUA指令碼來實現。


原理:MySQLProxy 實際上是在客戶端請求與MySQLServer 之間建立了一個連線池。所有客戶端請求都是發向MySQLProxy,然後經由MySQLProxy 進行相應的分析,判斷出是讀操作還是寫操作,分發至對應的MySQLServer 上。對於多節點Slave叢集,也可以起做到負載均衡的效果。


2.利用Amoeba實現資料切分及整合


Amoeba是一個基於Java開發的,專注於解決分散式資料庫資料來源整合Proxy程式的開源框架,Amoeba已經具有Query路由,Query過濾,讀寫分離,負載均衡以及HA機制等相關內容。Amoeba主要解決的以下幾個問題:


資料切分後複雜資料來源整合;
提供資料切分規則並降低資料切分規則給資料庫帶來的影響;
降低資料庫與客戶端的連線數;
讀寫分離路由;


AmoebaFor MySQL 主要是專門針對MySQL資料庫的解決方案,前端應用程式請求的協議以及後端連線的資料來源資料庫都必須是MySQL。對於客戶端的任何應用程式來說,AmoebaForMySQL 和一個MySQL資料庫沒有什麼區別,任何使用MySQL協議的客戶端請求,都可以被AmoebaFor MySQL 解析並進行相應的處理。


Proxy程式常用的功能如讀寫分離,負載均衡等配置都在amoeba.xml中進行。Amoeba已經支援了實現資料的垂直切分和水平切分的自動路由,路由規則可以在rule.xml進行設定。


3.利用HiveDB實現資料切分及整合


HiveDB同樣是一個基於Java針對MySQL資料庫的提供資料切分及整合的開源框架,只是目前的HiveDB僅僅支援資料的水平切分。主要解決大資料量下資料庫的擴充套件性及資料的高效能訪問問題,同時支援資料的冗餘及基本的HA機制。


HiveDB的實現機制與MySQLProxy 和Amoeba有一定的差異,他並不是藉助MySQL的Replication功能來實現資料的冗餘,而是自行實現了資料冗餘機制,而其底層主要是基於HibernateShards 來實現的資料切分工作。資料切分與整合中可能存在的問題


引入分散式事務的問題?


一旦資料進行切分被分別存放在多個MySQLServer中之後,不管我們的切分規則設計的多麼的完美(實際上並不存在完美的切分規則),都可能造成之前的某些事務所涉及到的資料已經不在同一個MySQLServer 中了。


==>將一個跨多個資料庫的分散式事務分拆成多個僅處於單個資料庫上面的小事務,並透過應用程式來總控各個小事務。


跨節點Join的問題?


==>先從一個節點取出資料,然後根據這些資料,再到另一個表中取資料.
==>使用Federated儲存引擎,問題是:乎如果遠端的表結構發生了變更,本地的表定義資訊是不會跟著發生相應變化的。


跨節點合併排序分頁問題?


==>Join本身涉及到的多個表之間的資料讀取一般都會存在一個順序關係。但是排序分頁就不太一樣了,排序分頁的資料來源基本上可以說是一個表(或者一個結果集),本身並不存在一個順序關係,所以在從多個資料來源取資料的過程是完全可以並行的。這樣,排序分頁資料的取數效率我們可以做的比跨庫Join更高,所以帶來的效能損失相對的要更小。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15498/viewspace-1984588/,如需轉載,請註明出處,否則將追究法律責任。

相關文章