數據庫垂直拆分 水平拆分
《大型網站系統與Java中間件實踐》本書圍繞大型網站和支撐大型網站架構的 Java 中間件的實踐展開介紹。從分布式系統的知識切入,讓讀者對分布式系統有基本的了解;然後介紹大型網站隨著數據量、訪問量增長而發生的架構變遷;接著講述構建 Java 中間件的相關知識;之後的幾章都是根據筆者的經驗來介紹支撐大型網站架構的 Java 中間件系統的設計和實踐。本節為大家介紹專庫專用,數據垂直拆分。
AD:
51CTO 網+ 第十二期沙龍:大話數據之美_如何用數據驅動用戶體驗
2.2.7 讀寫分離後,數據庫又遇到瓶頸
通過讀寫分離以及在某些場景用分布式存儲系統替換關系型數據庫的方式,能夠降低主庫的壓力,解決數據存儲方面的問題。不過隨著業務的發展,我們的主庫也會遇到瓶頸。我們的網站演進到現在,交易、商品、用戶的數據還都在一個數據庫中。盡管采取了增加緩存、讀寫分離的方式,這個數據庫的壓力還是在繼續增加,因此我們需要去解決這個問題,我們有數據垂直拆分和水平拆分兩種選擇。
2.2.7.1 專庫專用,數據垂直拆分
垂直拆分的意思是把數據庫中不同的業務數據拆分到不同的數據庫中。結合現在的例子,就是把交易、商品、用戶的數據分開,如圖2-20 所示。
這樣的變化給我們帶來的影響是什麽呢?應用需要配置多個數據源,這就增加了所需的配置,不過帶來的是每個數據庫連接池的隔離。不同業務的數據從原來的一個數據庫中拆分到了多個數據庫中,那麽就需要考慮如何處理原來單機中跨業務的事務。一種辦法是使用分布式事務,其性能要明顯低於之前的單機事務;而另一種辦法就是去掉事務或者不去追求強事務支持,則原來在單庫中可以使用的表關聯的查詢也就需要改變實現了。
對數據進行垂直拆分之後,解決了把所有業務數據放在一個數據庫中的壓力問題。並且也可以根據不同業務的特點進行更多優化。
2.2.7.2 垂直拆分後的單機遇到瓶頸,數據水平拆分
與數據垂直拆分對應的還有數據水平拆分。數據水平拆分就是把同一個表的數據拆到兩個數據庫中。產生數據水平拆分的原因是某個業務的數據表的數據量或者更新量達到了單個數據庫的瓶頸,這時就可以把這個表拆到兩個或者多個數據庫中。數據水平拆分與讀寫分離的區別是,讀寫分離解決的是讀壓力大的問題,對於數據量大或者更新量的情況並不起作用。數據水平拆分與數據垂直拆分的區別是,垂直拆分是把不同的表拆到不同的數據庫中,而水平拆分是把同一個表拆到不同的數據庫中。例如,經過垂直拆分後,用戶表與交易表、商品表不在一個數據庫中了,如果數據量或者更新量太大,我們可以進一步把用戶表拆分到兩個數據庫中,它們擁有結構一模一樣的用戶表,而且每個庫中的用戶表都只涵蓋了一部分的用戶,兩個數據庫的用戶合在一起就相當於沒有拆分之前的用戶表。我們先來簡單看一下引入數據水平拆分後的結構,如圖2-21 所示。
我們來分析一下水平拆分後給業務應用帶來的影響。
首先,訪問用戶信息的應用系統需要解決SQL 路由的問題,因為現在用戶信息分在了兩個數據庫中,需要在進行數據庫操作時了解需要操作的數據在哪裏。
此外,主鍵的處理也會變得不同。原來依賴單個數據庫的一些機制需要變化,例如原來使用Oracle 的Sequence 或者MySQL 表上的自增字段的,現在不能簡單地繼續使用了。並且在不同的數據庫中也不能直接使用一些數據庫的限制來保證主鍵不重復了。
最後,由於同一個業務的數據被拆分到了不同的數據庫中,因此一些查詢需要從兩個數據庫中取數據,如果數據量太大而需要分頁,就會比較難處理了。
不過,一旦我們能夠完成數據的水平拆分,我們將能夠很好地應對數據量及寫入量增長的情況。具體如何完成數據水平拆分,在後面分布式數據訪問層的章節中我們將進行更加詳細的介紹。
2.2.8 數據庫問題解決後,應用面對的新挑戰
2.2.8.1 拆分應用
前面所講的讀寫分離、分布式存儲、數據垂直拆分和數據水平拆分都是在解決數據方面的問題。下面我們來看看應用方面的變化。
之前解決了應用服務器從單機到多機的擴展,應用就可以在一定範圍內水平擴展了。隨著業務的發展,應用的功能會越來越多,應用也會越來越大。我們需要考慮如何不讓應用持續變大,這就需要把應用拆開,從一個應用變為兩個甚至多個應用。我們來看兩種方式。
第一種方式,根據業務的特性把應用拆開。在我們的例子中,主要的業務功能分為三大部分:交易、商品和用戶。我們可以把原來的一個應用拆成分別以交易和商品為主的兩個應用,對於交易和商品都會有涉及用戶的地方,我們讓這兩個系統自己完成涉及用戶的工作,而類似用戶註冊、登錄等基礎的用戶工作,可以暫時交給兩系統之一來完成(註意,我們在這裏主要是通過例子說明拆分的做法),如圖2-22 所示,這樣的拆分可以使大的應用變小。
我們還可以按照用戶註冊、用戶登錄、用戶信息維護等再拆分,使之變成三個系統。不過,這樣拆分後在不同系統中會有一些相似的代碼,例如用戶相關的代碼。如何能夠保證這部分代碼的一致以及如何對其復用是需要解決的問題。此外,按這樣的方式拆分出來的新系統之間一般沒有直接的相互調用。而且,新拆出來的應用可能會連接同樣的數據庫。
來看一個具體的例子,如圖2-23 所示。
我們根據業務的不同功能拆分了幾個業務應用,而且這些業務應用之間不存在直接的調用,它們都依賴底層的數據庫、緩存、文件系統、搜索等。這樣的應用拆分確實能夠解決當下的一些問題,不過也有一些缺點。
2.2.8.2 走服務化的路
我們再來看一下服務化的做法。圖2-24 是一個示意圖。從中可以看到我們把應用分為了三層,處於最上端的是Web 系統,用於完成不同的業務功能;處於中間的是一些服務中心,不同的服務中心提供不同的業務服務;處於下層的則是業務的數據庫。當然,我們在這個圖中省去了緩存等基礎的系統,因此可以說是服務化系統結構的一個簡圖。
圖2-24 與之前的圖相比有幾個很重要的變化。首先,業務功能之間的訪問不僅是單機內部的方法調用了,還引入了遠程的服務調用。其次,共享的代碼不再是散落在不同的應用中了,這些實現被放在了各個服務中心。第三,數據庫的連接也發生了一些變化,我們把與數據庫的交互工作放到了服務中心,讓前端的Web 應用更加註重與瀏覽器交互的工作,而不必過多關註業務邏輯的事情。連接數據庫的任務交給相應的業務服務中心了,這樣可以降低數據庫的連接數。而服務中心不僅把一些可以共用的之前散落在各個業務的代碼集中了起來,並且能夠使這些代碼得到更好的維護。第四,通過服務化,無論是前端Web 應用還是服務中心,都可以是由固定小團隊來維護的系統,這樣能夠更好地保持穩定性,並能更好地控制系統本身的發展,況且穩定的服務中心日常發布的次數也遠小於前端Web 應用,因此這個方式也減小了不穩定的風險。
要做到服務化還需要一些基礎組件的支撐,在後面服務框架的章節我們會具體介紹。
通過某種特定的條件,將存放在同一個數據庫中的數據分散存放到多個數據庫上,實現分布存儲,通過路由規則路由訪問特定的數據庫,這樣一來每次訪問面對的就不是單臺服務器了,而是N臺服務器,這樣就可以降低單臺機器的負載壓力。提示:sqlserver 2005版本之後,可以友好的支持“表分區”。
垂直(縱向)拆分:是指按功能模塊拆分,比如分為訂單庫、商品庫、用戶庫...這種方式多個數據庫之間的表結構不同。
水平(橫向)拆分:將同一個表的數據進行分塊保存到不同的數據庫中,這些數據庫中的表結構完全相同。
▲(縱向拆分)
▲(橫向拆分)
1,實現原理:使用垂直拆分,主要要看應用類型是否合適這種拆分方式,如系統可以分為,訂單系統,商品管理系統,用戶管理系統業務系統比較明的,垂直拆分能很好的起到分散數據庫壓力的作用。業務模塊不明晰,耦合(表關聯)度比較高的系統不適合使用這種拆分方式。但是垂直拆分方式並不能徹底解決所有壓力問題,例如 有一個5000w的訂單表,操作起來訂單庫的壓力仍然很大,如我們需要在這個表中增加(insert)一條新的數據,insert完畢後,數據庫會針對這張表重新建立索引,5000w行數據建立索引的系統開銷還是不容忽視的,反過來,假如我們將這個表分成100個table呢,從table_001一直到table_100,5000w行數據平均下來,每個子表裏邊就只有50萬行數據,這時候我們向一張只有50w行數據的table中insert數據後建立索引的時間就會呈數量級的下降,極大了提高了DB的運行時效率,提高了DB的並發量,這種拆分就是橫向拆分
2,實現方法:垂直拆分,拆分方式實現起來比較簡單,根據表名訪問不同的數據庫就可以了。橫向拆分的規則很多,這裏總結前人的幾點,
(1)順序拆分:如可以按訂單的日前按年份才分,2003年的放在db1中,2004年的db2,以此類推。當然也可以按主鍵標準拆分。
優點:可部分遷移
缺點:數據分布不均,可能2003年的訂單有100W,2008年的有500W。
(2)hash取模分: 對user_id進行hash(或者如果user_id是數值型的話直接使用user_id的值也可),然後用一個特定的數字,比如應用中需要將一個數據庫切分成4個數據庫的話,我們就用4這個數字對user_id的hash值進行取模運算,也就是user_id%4,這樣的話每次運算就有四種可能:結果為1的時候對應DB1;結果為2的時候對應DB2;結果為3的時候對應DB3;結果為0的時候對應DB4,這樣一來就非常均勻的將數據分配到4個DB中。
優點:數據分布均勻
缺點:數據遷移的時候麻煩;不能按照機器性能分攤數據 。
(3)在認證庫中保存數據庫配置
就是建立一個DB,這個DB單獨保存user_id到DB的映射關系,每次訪問數據庫的時候都要先查詢一次這個數據庫,以得到具體的DB信息,然後才能進行我們需要的查詢操作。
優點:靈活性強,一對一關系
缺點:每次查詢之前都要多一次查詢,會造成一定的性能損失。
數據庫垂直拆分 水平拆分