單數據庫架構
一個項目在初期的時候,爲了儘量快地驗證市場,其對業務系統的最大要求是快速實現。在這個階段,代碼開發人員爲了能快速實現業務系統,通常都是將全部層級(MVC)的業務代碼都寫在同一個項目中,全部的業務數據都存放在同一個數據庫中。此時,項目的總體架構圖以下所示:前端
從上圖能夠看到,咱們在一個項目中集中了註冊、登錄、購物三個模塊的業務代碼,而且這三個業務模塊都讀取同一個業務數據庫。程序員
但隨着項目的不斷推動,用戶量不斷增加,單臺應用服務器已經沒法承受如此巨大的流量了。此時常見的作法是把項目進行分佈式部署,分散單臺服務器的流量,從而能夠暫時緩解用戶增加帶來的應用服務器壓力。此時的項目架構圖以下所示:數據庫
但隨着咱們部署的應用服務器愈來愈多,後端的單臺數據庫服務器已經沒法承受如此巨大的流量了。爲了儘快緩解用戶訪問壓力,咱們通常是在應用服務器與數據庫服務器中間加多一個緩存層,經過緩存能夠抵消掉一部分的數據庫查詢操做。此時的項目架構圖以下所示:後端
可是增長數據庫緩存層只能緩解數據庫訪問壓力,攔截部分數據庫訪問請求。隨着用戶訪問量的進一步增加,數據庫訪問的瓶頸仍是會進一步凸顯。這個時候,咱們不得不對數據層的架構進行改造。緩存
主從數據庫架構
這個時候經常使用的解決方案就是將本來單臺數據庫服務器變成主從模式的數據庫服務器,即一臺數據庫做爲主庫支持寫入數據,一臺數據庫做爲讀庫支持查詢數據。此時項目的架構圖以下所示:服務器
咱們經過數據庫主從同步實現了讀寫分離,將全部讀操做都引導到從庫進行,將全部寫操做都引導到主庫進行。markdown
由於咱們對數據庫層進行了改造,規定全部讀數據庫操做要訪問從庫,全部寫數據庫操做要訪問主庫,那麼咱們就必須對原來的代碼進行改造。網絡
上面是改造前的代碼,不管是讀操做仍是寫操做,咱們都使用同一個數據源進行操做。但爲了適應新的數據庫架構,咱們必須在代碼中手動判斷應該請求哪一個數據源。架構
通過修改後的代碼,開發根據自身經驗判斷應該選擇哪一個數據源進行操做。當是讀操做的時候,咱們選擇 readTemplate。當是寫操做的時候,咱們選擇 writeTemplate。less
但做爲一個程序員,咱們隱隱約約以爲識別應該用哪一個數據源這個判斷不該該人工判斷,而應該自動讓代碼去判斷。畢竟這個判斷的模式很簡單 —— 若是是 select 那麼就用讀的數據源,若是是其餘那麼就用寫的數據源。
其實這個就是 MyCat 的用途之一,即做爲一個數據庫中間件去解決數據源判斷問題。若是咱們使用 MyCat 做爲數據庫中間件,那麼咱們不須要關心我應該使用哪一個數據源。MyCat 幫咱們屏蔽了不一樣數據源的差別,對於咱們來講就只有一個數據源,這個數據源能處理寫操做,也能處理讀操做。上面查詢和插入的代碼就能夠變成下面這樣:
實現了主從數據庫架構,再使用 MyCat,你發現咱們並不須要去修改太多的代碼,只須要將數據源改成 MyCat 地址便可。MyCat 自動把咱們全部的語句發送給後端的 MySQL 服務器。
當咱們使用了主從數據庫架構以後,咱們會發現咱們能支撐更多的用戶訪問和請求了。但隨着業務的進一步發展,其實能夠發現會存在一些問題:
- 當咱們修改了註冊模塊的時候,咱們須要整個項目都發布一次,這樣會影響到登陸、購物模塊的正常使用。
- 即便每次改動的代碼即便很小,咱們仍是須要發佈整個項目包,這使得每次發佈的代碼包很是巨大。
- 隨着業務量的不斷增加,咱們會發現即便實現了主從的讀寫分離,數據庫的壓力也是很是大,彷佛快要承受不了了。
上面說的這些問題只是實戰中遇到的一部分問題,事實上遇到的問題只會更多不會更少,並且隨着業務的不斷髮展會越發凸顯。
垂直切分數據庫架構
此時爲了各個業務模塊不互相影響,咱們把應用層進行垂直拆分,即把註冊模塊、登錄模塊、購物模塊都單獨做爲一個應用系統,分別讀寫獨立的數據庫服務器。此時,咱們的系統架構圖以下圖所示:
實現了垂直拆分以後,咱們能夠成功解決上面說到的三個問題:業務模塊相互影響問題、單數據庫壓力問題。
可是隨着業務的進一步擴大,咱們又增長了許多業務模塊:客服模塊、錢包模塊、我的中心模塊、收藏夾模塊、訂單模塊等。按照咱們以前所設計的數據庫架構,咱們會存在許多個數據源,這些數據源分散在各個項目中:
- 用戶數據庫 192.168.0.1
- 商品數據庫 192.168.0.2
- 短信數據庫 192.168.0.3
- 客服數據庫 192.168.0.4
- 錢包數據庫 192.168.0.5
- ……
對於一個項目管理者來講,這麼多的數據源分散在不一樣項目中,怎麼統一管理是一個問題。不少時候咱們都很難記住這個項目鏈接的是哪一個數據庫,那個項目鏈接的是哪一個數據庫。
但若是你使用了 MyCat 做爲數據庫中間件的話,MyCat 就能夠幫你解決這個問題。對於全部項目來講,它們只須要統一鏈接 MyCat 對外提供的一個地址,而 MyCat 則幫這些項目聯繫全部後端的 MySQL 數據庫。對於前端的項目倆說,它們只知道 MyCat 這個數據庫中間件,而不須要去理會我到底鏈接哪一個數據庫,MyCat 經過自身配置能夠完成這個任務。
水平切分數據庫架構
當數據庫架構經歷了主從架構、垂直拆分架構以後,應對通常的業務讀寫是沒有什麼問題了。但對於一些核心的業務數據,可能仍是會有瓶頸問題,例如用戶模塊。
對於一些用戶量高達一個億的用戶系統來講,即便通過主從架構、垂直拆分架構的優化,但其用戶數據庫的單個表裏須要存儲的數據仍是高達一個億的大小。若是咱們把全部的數據都存放在一個表裏,不管是註冊時的插入數據,或者是登錄時的查詢數據,勢必會變得很慢。
這時候,咱們就不得不對這些高數據量的核心業務表進行水平拆分,即將海量的數據記錄拆分到多張表中保存。例如咱們一開始可能只有一張 User 表,咱們將 User 表按照用戶 ID 對 1000 取餘進行拆分,那麼咱們就會有 1000 張表,分別是 User_000 至 User_999。此時,項目的架構圖以下所示:
當咱們在代碼中查詢用戶數據時,咱們先根據用戶 ID 取餘判斷其應該操做的表,以後再查詢對應的表。例如 UserId 爲 90749738 的用戶就應該查詢 User_38 表,UserId 爲 74847383 的用戶就應該查詢 User_83 表。
經過水平拆分,咱們成功解決了海量數據核心業務表的讀寫瓶頸問題。但此時在代碼層面上有一個問題出現了,那就是咱們須要在查詢數據庫以前,根據 UserId 去判斷應該查詢哪一個表,這個操做對於全部業務模塊來講都是高度一致的,應該抽離成一個公用的項目。
與判斷應該使用讀數據源仍是寫數據源一致,咱們都以爲這樣機械的任務不該該丟給程序員作,應該讓機器去作。這其實就是 MyCat 能夠幫咱們作的事情:MyCat 經過配置一系列的分庫分表規則,讓 MyCat 幫咱們自動判斷應該查詢哪個分表。經過使用 MyCat 數據庫中間件,咱們能夠省去在代碼層判斷查詢哪一個表的冗餘代碼,從而讓開發人員更專一於業務邏輯的開發。
總結
從單一的數據庫架構,到主從讀寫分離的數據庫架構,再到垂直拆分、水平拆分的數據庫架構。咱們能夠看到 MyCat 幫咱們解決了讀寫數據源判斷、繁雜數據源地址、分表判斷這三個機械的重複性的問題。
上面說到的三個功能就是 MyCat 誕生初期的最基本功能。但 MyCat 發展至今,其功能已經遠遠超過上面說的這三個。例如 MyCat 支持主從切換功能,當數據庫主庫發生網絡問題或其餘故障時,MyCat 能夠自動切換到從庫,從而保證正常讀寫功能的進行。
總的來講,MyCat 的定位是一個數據庫中間件。但凡全部處於應用層和數據層之間的事情,MyCat 均可以作。