mysql實現資料切分的方法:1、使用資料的垂直切分;2、使用資料的水平切分;3、利用MySQL Proxy實現資料切分及整合;4、利用Amoeba實現資料切分;5、利用HiveDB實現資料切分及整合。
#更多相關免費學習推薦:mysql教學
# #(視訊)
mysql實作資料切分的方法: 何謂資料切分簡單來說,就是指透過某種特定的條件,將存放在同一個資料庫中的資料分散存放到多個資料庫(主機)上面,以達到分散單一裝置負載的效果。資料的切分同時還可以提高系統的整體可用性,因為單一設備Crash之後,只有整體資料的某部分不可用,而不是所有的資料。
資料的切分(Sharding)根據其切分規則的類型,可以分為兩種切分模式。一種是依照不同的表(或Schema)來切分到不同的資料庫(主機)之上,這種切分可以稱為資料的垂直(縱向)切分;另外一種則是根據表中資料的邏輯關係,將同一個表中的資料依照某種條件拆分到多台資料庫(主機)上,這種切分稱之為資料的水平(橫向)切分。
垂直切分的最大特點就是規則簡單,實施也更為方便,尤其適合各業務之間的耦合度非常低、相互影響很小、業務邏輯非常清晰的系統。在這種系統中,可以很容易做到將不同業務模組所使用的表分拆到不同的資料庫中。根據不同的表格來進行拆分,對應用程式的影響也更小,拆分規則也會比較簡單清晰。 水平切分與垂直切分相比,稍微複雜一些。因為要將同一個表中的不同資料拆分到不同的資料庫中,對於應用程式來說,拆分規則本身就較根據表名來拆分更為複雜,後期的資料維護也會更複雜。
當某個(或某些)表的資料量和存取量特別大,透過垂直切分將其放在獨立的裝置上後仍然無法滿足效能要求時,就必須將垂直切分和水平切分結合,先垂直切分,然後再水平切分,這樣才能解決這個超大型表的效能問題。
以下就針對垂直、水平及組合切分這三種資料切分方式的架構實現及切分後資料的整合進行對應的分析。
資料的垂直切分我們先來看一下,資料的垂直切分到底是如何切分的。資料的垂直切分,也可以稱為縱向切分。將資料庫想像成由很多一大塊的「資料塊」(表)組成,垂直地將這些「資料塊」切開,然後把它們分散到多台資料庫主機上面。這樣的切分方法就是垂直(縱向)的資料切分。
一個架構設計較好的應用系統,其整體功能肯定是由很多功能模組所組成的,而每一個功能模組所需的資料對應到資料庫中就是一個或多個表。而在架構設計中,各個功能模組相互之間的交互點越統一、越少,系統的耦合度就越低,系統各模組的維護性及擴展性也越好。這樣的系統,要實現資料的垂直切分也就越容易。
###功能模組越清晰,耦合度越低,資料垂直切分的規則定義就越容易。完全可以根據功能模組來進行資料的切分,不同功能模組的資料存放於不同的資料庫主機中,可以很容易就避免跨資料庫的Join存在,同時系統架構也非常清晰。 ######當然,很難有系統能夠做到所有功能模組使用的表完全獨立,根本不須要訪問對方的表,或者須要將兩個模組的表進行Join操作。在這種情況下,就必須根據實際的應用場景進行評估權衡。決定是遷就應用程式將需要Join的表的相關模組都存放在同一個資料庫中,還是讓應用程式做更多的事情——完全透過模組介面取得不同資料庫中的數據,然後在程式中完成Join操作。 ######一般來說,如果是一個負載相對不大,而且表關聯又非常頻繁的系統,那可能資料庫讓步,將幾個相關模組合併在一起,減少應用程式工作的方案可以減少較多的工作量,是可行的方案。 ######當然,透過資料庫的讓步,讓多個模組集中共用資料來源,實際上也是間接默許了各模組架構耦合度增大的發展,可能會惡化以後的架構。尤其是當發展到某個階段,發現資料庫實在無法承擔這些表所帶來的壓力,不得不面臨再次切分時,所帶來的架構改造成本可能遠大於最初就使用切分的架構設計。 ###所以,在資料庫進行垂直切分的時候,如何切分、切分到什麼樣的程度,是比較考驗人的難題。這只能在實際的應用場景中透過平衡各方面的成本和效益,才能分析出一個真正適合自己的分割方案。
例如在本文所使用的範例係統的example資料庫中,我們簡單分析一下,然後設計一個簡單的切分規則,進行一次垂直拆分。
系統功能基本上可以分為4個功能模組:使用者、群組訊息、相簿以及事件,分別對應為以下這些表:
使用者模組表: user,user_profile,user_group,user_photo_album
群組討論表:groups,group_message,group_message_content,top_message
相簿相關表:photo,photo_album ,photo_album_relation,photo_comment
事件資訊表:event
初略一看,沒有哪個模組可以脫離其他模組獨立存在,模組與模組之間都存在著關係,莫非無法切分?
當然不是,再稍微深入分析一下,可以發現,雖然各個模組所使用的表之間都有關聯,但是關聯關係還算清晰,也比較簡單。
群組討論模組和使用者模組之間主要存在透過使用者或群組關係來進行關聯。一般都會透過使用者的id或nick_name及group的id來進行關聯,透過模組之間的介面實作不會帶來太多麻煩。
相簿模組僅與使用者模組存在使用者的關聯。這兩個模組之間的關聯基本上只有透過使用者id關聯的內容,簡單清晰,介面明確。
事件模組與各個模組可能都有關聯,但是都只關注其各個模組中物件的ID訊息,同樣比較容易分拆。
所以,第一步可以將資料庫依照功能模組相關的表進行一次垂直拆分,每個模組所涉及的表單獨分到一個資料庫中,模組與模組之間的表關聯在應用系統端都透過介面來處理。如資料垂直切分示意圖(圖1)所示:
透過這樣的垂直切分之後,之前只能透過一個資料庫來提供的服務,就被分拆成4個資料庫來提供服務,服務能力自然增加幾倍了。
垂直切分的優點:
資料庫的拆分簡單明了,拆分規則明確;
應用程式模組清晰明確,整合容易;
資料維護方便易行,容易定位。
垂直切分的缺點:
部分錶關聯無法在資料庫層級完成,要在程式中完成;
#對於存取極其頻繁且資料量超大的表仍然存在效能瓶頸,不一定能滿足要求;
事務處理相對複雜;
切分達到一定程度之後,擴展性會受到限制;
#過度切分可能會帶來系統過於複雜而難以維護。
針對於垂直切分可能遇到資料切分及交易問題,在資料庫層面實在是很難找到一個較好的處理方案。在實際應用案例中,資料庫的垂直切分大多是與應用系統的模組相對應的,而同一個模組的資料來源存放於同一個資料庫中,可以解決模組內部的資料關聯問題。而模組與模組之間,則透過應用程式以服務介面的方式來相互提供所需的資料。雖然這樣做在資料庫的整體操作次數方面確實會有所增加,但是在系統整體擴展性及架構模組化方面,都是有益的。可能某些操作的單次回應的時間會稍有增加,但是系統的整體效能很可能反而會有一定的提升。而擴展瓶頸問題,就只能靠下一節將要介紹的資料水平切分架構來解決了。
資料的水平切分
上面一節分析介紹了資料的垂直切分,本節分析資料的水平切分。數據的垂直切分基本上可以簡單地理解為按照表或模組來切分數據,而水平切分則不同。一般來說,簡單的水平切分主要是將某個存取極為平凡的表再依照某個欄位的某種規則分散到多個表中,每個表包含一部分資料。
簡單來說,可以將資料的水平切分理解為依照資料行的切分,就是將表格中的某些行切分到一個資料庫,而另外的某些行又切分到其他的資料庫中。當然,為了能夠比較容易地判定各行資料被切分到哪個資料庫中了,切分總是須要按照某種特定的規則來進行的:如根據某個數字類型字段基於特定數目取模,某個時間類型欄位的範圍,或某個字元類型欄位的hash值。如果整個系統中大部分核心表都可以透過某個欄位來進行關聯,那麼這個欄位自然是一個進行水平分區的上上之選了,當然,非常特殊無法使用的情況除外。
一般來說,像現在非常熱門的Web 2.0類型網站,基本上大部分資料都能夠透過會員使用者資訊關聯上,可能許多核心表都非常適合透過會員ID來進行資料的水平切分。而像論壇社群討論系統,就更容易切分了,可以依照論壇編號來進行水平切分。切分之後基本上不會出現各個函式庫之間的互動。
如果範例係統的所有資料都是和使用者關聯的,那麼就可以根據使用者來進行水平拆分,將不同使用者的資料切分到不同的資料庫中。當然,唯一區別是用戶模組中的groups表和用戶沒有直接關係,所以groups不能根據用戶來進行水平拆分。對於這種特殊情況下的表,完全可以獨立出來,放在一個獨立的資料庫中。其實這個做法可以說是利用了前面一節所介紹的「資料的垂直切分」方法,將在下一節中更為詳細地介紹這種垂直切分與水平切分同時使用的聯合切分方法。
所以,對於範例資料庫來說,大部分的表都可以根據使用者ID來進行水平切分。不同使用者相關的資料進行切分之後存放在不同的資料庫中。如將所有用戶ID透過被2取模然後分別存放於兩個不同的資料庫中。每個和使用者ID關聯上的表格都可以這樣切分。這樣,基本上每個使用者相關的數據,都在同一個資料庫中,即使須要關聯,也非常容易實現。
可以透過水平切分示意圖(圖2)更直觀地展示水平切分相關資訊:
水平切分的優點:
表格關聯基本上能夠在資料庫端全部完成;
不會存在某些超大型資料量和高負載的表遇到瓶頸的問題;
#應用程式端整體架構改變相對較少;
事務處理相對簡單;
只要切分規則能夠定義好,基本上較難遇到擴展性限制。
水平切分的缺點:
切分規則相對複雜,很難抽像出一個能夠滿足整個資料庫的切分規則;
後期資料的維護難度增加,人為手動定位資料更困難;
應用系統各模組耦合度較高,可能會對後面資料的遷移拆分造成一定的困難。
垂直與水平聯合切分的使用
#前面兩節內容中,分別了解了「垂直」和「水平」這兩種切分方式的實作和切分之後的架構訊息,以及兩種架構各自的優缺點。但在實際的應用場景中,除了那些負載並不是太大、業務邏輯也相對簡單的系統可以透過上面兩種切分方法之一來解決擴展性問題之外,恐怕其他大部分業務邏輯複雜、系統負載大的系統,都無法透過上面任何一種資料的切分方法來實現較好的擴展性,這就需要將上述兩種切分方法結合使用,不同的場景使用不同的切分方法。
本節將結合垂直切分和水平切分各自的優缺點,進一步完善整體架構,並提高系統的擴展性。
一般來說,資料庫中的所有表格很難透過某一個(或少數幾個)欄位全部關聯起來,所以僅僅透過資料的水平切分無法解決所有問題。而垂直切分也只能解決部分問題,對於那些負載非常高的系統,即使只是單一表格都無法透過單一資料庫主機來承擔其負載。必須結合「垂直」和「水平」兩種切分方式,充分利用兩者的優點,避開其缺點。
每一個應用系統的負載都是一步一步增長上來的,在開始遇到效能瓶頸的時候,大多數架構師和DBA都會選擇先進行資料的垂直拆分,因為這樣的成本最低,最符合這個時期所追求的最大投入產出比。然而,隨著業務的不斷擴張,系統負載的持續成長,在系統穩定一段時期之後,經過了垂直分割後的資料庫叢集可能再次不堪重負,遇到了效能瓶頸。
此時該如何抉擇?是再次進一步細分模組,還是尋求其他的解決方案?如果我們再像最開始一樣繼續細分模組,進行資料的垂直切分,那可能在不久的將來,又會遇到現在所面臨的同樣問題。而且隨著模組的不斷細化,應用系統的架構也會越來越複雜,整個系統很可能會出現失控的局面。
這時候就必須要利用資料水準切分的優勢來解決遇到的問題。而且,完全不必在使用資料水平切分時,推倒先前進行資料垂直切分的成果,而是在其基礎上利用水平切分的優勢來避開垂直切分的弊端,解決系統複雜性不斷擴大的問題。而水平分割的弊端(規則難以統一)也已經被先前的垂直切分解決掉了,讓水平切分可以進行得心應手。
對於範例資料庫,假設在最開始進行了資料的垂直切分,然而隨著業務的不斷增長,資料庫系統遇到了瓶頸,我們選擇重構資料庫叢集的架構。如何重構?考慮到之前已經做好了資料的垂直切分,而且模組結構清晰明確,而業務成長的勢頭越來越猛,即使現在再次拆分模組,也堅持不了太久。所以選擇了在垂直切分的基礎上再進行水平切分。
經歷過垂直切分後的資料庫叢集中的各個資料庫都只有一個功能模組,而每個功能模組中的所有資料表基本上都會與某個欄位進行關聯。如用戶模組全部都可以透過用戶ID進行切分,群組討論模組則都透過群組ID來切分,相簿模組則根據相簿ID來進切分,最後的事件通知資訊表考慮到資料的時限性(僅訪問最近某個事件段的資訊),則按時間來切分。
組合切分展示了切分後的整個架構:
實際上,在許多大型的應用系統中,垂直切分和水平切分基本上是並存的,而且經常不斷地交替進行,以增加系統的擴展能力。我們在應對不同的應用場景時,也須要充分考慮到這兩種切分方法的限制及優勢,在不同的時期(負載壓力)使用不同的方式。
聯合切分的優點:
#可以充分利用垂直切分和水平切分各自的優勢而避免各自的缺陷;
#讓系統擴展性得到最大化提升。
聯合切分的缺點:
資料庫系統架構較為複雜,維護難度較大;
透過前面的章節,已經清楚了透過資料庫的資料切分可以大大提高系統的擴展性。但是,資料庫中的資料經過垂直和(或)水平切分被存放在不同的資料庫主機之後,應用系統面臨的最大問題就是如何讓這些資料來源得到較好的整合,也許這也是許多讀者非常關心的一個問題。本節主要的內容是分析各種可以幫助我們實現資料切分及資料整合的整體解決方案。 資料的整合很難依賴資料庫本身來達到,雖然MySQL存在Federated儲存引擎,可以解決部分類似的問題,但在實際應用場景中卻很難較好地運用。那該如何來整合這些分散在各個MySQL主機上的資料來源呢?
總的來說,有兩種解決想法:
在每個應用程式模組中配置管理自己需要的一個(或多個)資料來源,直接存取各個資料庫,在模組內完成資料的整合;透過中間代理層來統一管理所有的資料來源,後端資料庫叢集對前端應用程式透明。
可能90%以上的人在面對這兩種解決思路時都會傾向於選擇第二種,尤其是系統不斷龐大複雜的時候。確實,這是一個非常正確的選擇,雖然短期內須要付出的成本可能會相對大一些,但對整個系統的擴展性來說,是非常有幫助的。 所以,對於第一種解決思路就不過多分析了,以下重點分析第二種思路中的一些解決方案。自行開發中間代理層
在決定選擇透過資料庫的中間代理層來解決資料來源整合的架構方向之後,有不少公司(或企業)自行開發了符合自身應用特定場景的代理層應用程式。自行開發中間代理層可以最大程度地應對自身應用的特點,最大化客製化個人化需求,在面對變化的時候也可以靈活應對。這應該是自行開發代理層最大的優勢了。
當然,選擇自行開發,享受個人化客製化最大化樂趣的同時,自然也需要投入更多的成本來進行前期研發及後期的持續升級改進工作,而且本身的技術門檻可能也比簡單的Web應用更高。所以,在決定選擇自行開發之前,仍須要進行比較全面的評估。 由於自行開發更多時候考慮的是如何更好地適應自身應用系統,應對自身的業務場景,所以這裡也不好分析太多。以下將主要分析目前比較流行的幾種資料來源整合解決方案。 #########利用MySQL Proxy實作資料切分與整合#########MySQL Proxy是MySQL官方提供的資料庫代理程式層產品,和MySQL Server一樣,它也是一個基於GPL開源協定的開源產品。可用於監視、分析或傳輸它們之間的通訊訊息。它的靈活性允許最大限度地使用它,目前具備的功能主要有連接路由、Query分析、Query過濾和修改、負載平衡,以及基本的HA機制等。 ###實際上,MySQL Proxy本身並沒有上述所有的功能,而是提供了實現上述功能的基礎。要實現這些功能,也必須要我們自行編寫LUA腳本。
MySQL Proxy實際上是在客戶端請求與MySQL Server之間建立了一個連線池。所有客戶端請求都會傳送向MySQL Proxy,然後經由MySQL Proxy進行對應的分析,判斷出是讀取操作還是寫入操作,分送到對應的MySQL Server上。對於多節點Slave集群,也可以起到負載平衡的效果。如MySQL Proxy基本架構圖(圖4):
透過上面的架構簡圖,可以清楚地看到MySQL Proxy在實際應用中所處的位置,以及能做的基本事情。 MySQL Proxy詳細的實施細則在MySQL官方文件中有非常詳細的介紹和範例,有興趣的讀者朋友可以直接從MySQL官方網站免費下載或線上閱讀,這裡就不贅述。
利用Amoeba實作資料切分
Amoeba是一個基於Java開發的,專注於解決分散式資料庫資料來源整合Proxy程式的開源框架,基於GPL3開源協定.目前,Amoeba已經有Query路由、Query過濾、讀寫分離、負載平衡及HA機制等相關內容,如圖5所示。
Amoeba主要解決以下幾個問題:
資料切分後複雜資料來源整合;
提供資料切分規則並降低資料切分規則對資料庫帶來的影響;
降低資料庫與客戶端的連接數;
利用HiveDB實現資料切分與整合#
和前面的MySQL Proxy和Amoeba一樣,HiveDB同樣是一個基於Java針對MySQL資料庫的提供資料切分及整合的開源框架,只是目前的HiveDB只支援資料的水平切分。主要解決大數據量下資料庫的擴展性及資料的高效能存取問題,同時支援資料的冗餘及基本的HA機制。
HiveDB的實作機制與MySQL Proxy和Amoeba有一定的差異,它並不是藉助MySQL的Replication功能來實現資料的冗餘,而是自行實現了資料冗餘機制,而其底層主要是基於Hibernate Shards來實作資料切分工作。
在HiveDB中,透過使用者自訂的各種Partition keys(即制定資料切分規則),將資料分散到多個MySQL Server。存取時執行Query請求,則會自動分析過濾條件,並行從多個MySQL Server中讀取數據,並合併結果集傳回給客戶端應用程式。
單純從功能面講,HiveDB可能不如MySQL Proxy和Amoeba那麼強大,但其資料切分的想法與前面二者並無本質差異。此外,HiveDB並非只是一個開源愛好者所分享的內容,而是存在著商業公司支援的開源專案。
HiveDB官方網站上的HiveDB架構示意圖(圖7),描述了HiveDB如何來組織數據的基本信息,雖然不能詳細地表現出架構方面的信息,但是也基本可以展示其在數據切分上獨特的一面了。
其他實現資料切分及整合的解決方案
除了上面介紹的幾個資料切分及整合的整體解決方案之外,還存在許多其他的解決方案、如在MySQL Proxy的基礎上做進一步擴展的HSCALE,透過Rails建構的Spock Proxy,以及基於Pathon的Pyshards,等等。
不管大家選擇使用哪一種解決方案,整體設計思路基本上都不應該有任何變化,即透過資料的垂直和水平切分,增強資料庫的整體服務能力,讓應用系統的整體擴充能力盡量提升,擴充方式盡量方便。
只要透過中間層Proxy應用程式較好地解決了資料切分和資料來源整合問題,那麼資料庫的線性擴展能力將像應用程式一樣方便:只要透過添加廉價的PC Server伺服器,即可線性增加資料庫叢集的整體服務能力,讓資料庫不再輕易成為應用系統的效能瓶頸。
資料切分與整合中可能存在的問題
這裡,大家應該對資料切分與整合的實作有一定的認識了,或許很多讀者都已經根據各種解決方案的優劣基本選定了適合於自己應用場景的方案,後面的工作主要就是實施準備了。
在實作資料切分方案之前,仍要分析一些可能存在的問題。一般來說,可能遇到的問題主要有以下幾點:
引入分散式事務的問題;
跨節點Join的問題;
跨節點合併排序分頁問題。
引入分散式事務的問題
一旦資料進行切分被分別存放在多個MySQL Server中,不管切分規則設計得多完美(實際上並不存在完美的切分規則),都可能造成之前某些事務所涉及的資料已經不在同一個MySQL Server中了。
在這樣的場景下,如果應用程式仍然按照舊的方案,那麼勢必須要引入分散式事務來解決。而在MySQL各個版本中,只有從MySQL 5.0開始以後的各個版本才對分散式事務提供支持,而且目前僅有Innodb提供分散式事務支援。不過,即使我們剛好使用了支援分散式事務的MySQL版本,同時也使用Innodb儲存引擎,分散式事務本身對於系統資源的消耗量就很大,效能也不太高,引入分散式事務在異常處理方面會帶來很多比較難控制的問題。
怎麼辦?其實可以透過一個變通的方法來解決這個問題,首先要考慮的是:資料庫是否是唯一能夠解決事務的地方?其實不是這樣的,完全可以結合資料庫及應用程式來共同解決。各個資料庫解決自身的事務,然後透過應用程式來控制多個資料庫上的事務。
也就是說,只要我們願意,完全可以將一個跨多個資料庫的分散式事務分拆成多個僅處於單一資料庫上的小事務,並透過應用程式來總控各個小事務。當然,這樣做要求應用程式必須要有足夠的健壯性,當然也會為應用程式帶來一些技術難度。
跨節點Join的問題
上面介紹了可能引入分散式事務的問題,現在再看看需要跨節點Join的問題。資料切分之後,也許有些舊的Join語句無法繼續使用,因為Join所使用的資料來源可能被切分到多個MySQL Server中了。
怎麼辦?這個問題從MySQL資料庫角度來看,如果非得在資料庫端直接解決的話,恐怕只能透過MySQL一種特殊的儲存引擎Federated處理了。 Federated儲存引擎是MySQL解決類似Oracle的DB Link之類問題的方案。和Oracle DB Link的主要區別在於,Federated會保存一份遠端表結構的定義資訊在本地。乍一看,Federated確實是解決跨節點Join非常好的方案。但是我們也應該清楚一點,那就是如果遠端的表結構發生了變更,本地的表定義資訊是不會跟著改變的。如果在更新遠端表結構的時候並沒有更新本地的Federated表定義訊息,Query運行很可能出錯,無法得到正確的結果。
對待這類問題,還是推薦透過應用程式來處理,先在磁碟機表所在的MySQL Server中取出驅動程式結果集,然後根據驅動程式結果集再到被驅動程式表所在的MySQL Server中取出對應的數據。可能很多讀者朋友會認為這樣做將對性能產生一定的影響,是的,確實會有一定的負面影響,但除此之外,基本上沒有太多其他更好的解決辦法了。而且,由於資料庫透過較好的擴充功能之後,每台MySQL Server的負載就可以得到較好的控制,單純針對單一Query來說,其回應時間可能比不切分之前要提高一些,所以效能方面帶來的負面影響也不是太大。更何況,類似這種跨節點Join的需求也不是太多,相對於整體效能而言,可能也只是很小一部分而已。所以為了整體效能,偶爾犧牲一點點,其實是值得的,畢竟系統最佳化本身就是許多取捨和平衡的過程。
跨節點合併排序分頁問題
一旦進行了資料的水平切分之後,可能就不會只有跨節點Join無法正常運行,有些排序分頁的Query語句的資料來源可能也會被切割到多個節點,其直接後果就是這些排序分頁Query無法繼續正常運作。其實這和跨節點Join是一個道理,資料源存在於多個節點上,要透過一個Query來解決,就是一個跨節點Join操作。同樣Federated也可以部分解決,但存在的風險也是。但有一點不同:Join很多時候都有一個驅動與被驅動的關係,所以它所涉及的多個表之間的資料讀取一般會存在一個順序關係。但是排序分頁就不同了,排序分頁的資料來源基本上可以說是一個表(或一個結果集),並不存在順序關係,所以從多個資料來源取資料的過程是完全可以並行的。這樣,排序分頁資料的取數效率可以比跨庫Join更高,所以帶來的效能損失相對要小,在有些情況下可能比在原來未進行資料切分的資料庫中效率更高了。當然,無論是跨節點Join還是跨節點排序分頁,都會使應用程式伺服器消耗更多的資源,尤其是記憶體資源,因為在讀取存取及合併結果集的這個過程須要比不處理合併處理更多的數據。
以上是mysql如何實現資料切分的詳細內容。更多資訊請關注PHP中文網其他相關文章!