2.2.7 讀寫分離後,數據庫又遇到瓶頸前端
經過讀寫分離以及在某些場景用分佈式存儲系統替換關係型數據庫的方式,可以下降主庫的壓力,解決數據存儲方面的問題。不過隨着業務的發展,咱們的主庫也會遇到瓶頸。咱們的網站演進到如今,交易、商品、用戶的數據還都在一個數據庫中。儘管採起了增長緩存、讀寫分離的方式,這個數據庫的壓力仍是在繼續增長,所以咱們須要去解決這個問題,咱們有數據垂直拆分和水平拆分兩種選擇。mysql
2.2.7.1 專庫專用,數據垂直拆分sql
垂直拆分的意思是把數據庫中不一樣的業務數據拆分到不一樣的數據庫中。結合如今的例子,就是把交易、商品、用戶的數據分開,如圖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信息,而後才能進行咱們須要的查詢操做。
優勢:靈活性強,一對一關係
缺點:每次查詢以前都要多一次查詢,會形成必定的性能損失。