架構設計模式
前面的系列文章中從各個方面闡述了架構設計相關的理論和流程攘须,包括架構設計起源摧扇、架構設計的目的圣贸、常見架構復雜度分析、架構設計原則扛稽、架構設計流程等吁峻,掌握這些知識是做好架構設計的基礎
在具體的實踐過程中,為了更快、更好地設計出優(yōu)秀的架構用含,除了掌握這些基礎知識外矮慕,還需要掌握業(yè)界已經成熟的各種架構模式
接下來的文章會分幾期來介紹高性能數據庫集群:
- 第一種方式是“讀寫分離”,其本質是將訪問壓力分散到集群中的多個節(jié)點啄骇,但是沒有分散存儲壓力
- 第二種方式是“分庫分表”痴鳄,既可以分散訪問壓力,又可以分散存儲壓力
- 本文針對讀寫分離做相關講解
讀寫分離原理
- 讀寫分離的基本原理是將數據庫讀寫操作分散到不同的節(jié)點上缸夹,下面是其基本架構圖
- 讀寫分離的基本實現(xiàn):
- 數據庫服務器搭建主從集群痪寻,一主一從、一主多從都可以
- 數據庫主機負責讀寫操作虽惭,從機只負責讀操作
- 數據庫主機通過復制將數據同步到從機橡类,每臺數據庫服務器都存儲了所有的業(yè)務數據
- 業(yè)務服務器將寫操作發(fā)給數據庫主機,將讀操作發(fā)給數據庫從機
- 讀寫分離的實現(xiàn)邏輯并不復雜趟妥,但有兩個細節(jié)點將引入設計復雜度:主從復制延遲和分配機制
復制延遲
- 以 MySQL 為例猫态,主從復制延遲可能達到 1 秒,如果有大量數據同步披摄,延遲 1 分鐘也是有可能的
- 主從復制延遲會帶來一個問題:如果業(yè)務服務器將數據寫入到數據庫主服務器后立刻(1 秒內)進行讀取亲雪,此時讀操作訪問的是從機,主機還沒有將數據復制過來疚膊,到從機讀取數據是讀不到最新數據的义辕,業(yè)務上就可能出現(xiàn)問題
- 解決主從復制延遲有幾種常見的方法:
- 寫操作后的讀操作指定發(fā)給數據庫主服務器
- 例如,注冊賬號完成后寓盗,登錄時讀取賬號的讀操作也發(fā)給數據庫主服務器
- 這種方式和業(yè)務強綁定灌砖,對業(yè)務的侵入和影響較大,如果哪個新來的程序員不知道這樣寫代碼傀蚌,就會導致一個 bug
- 讀從機失敗后再讀一次主機
- 這就是通常所說的“二次讀取”基显,二次讀取和業(yè)務無綁定谅摄,只需要對底層數據庫訪問的 API 進行封裝即可秘症,實現(xiàn)代價較小站削,不足之處在于如果有很多二次讀取污桦,將大大增加主機的讀操作壓力
- 例如植影,黑客暴力破解賬號研铆,會導致大量的二次讀取操作拌汇,主機可能頂不住讀操作的壓力從而崩潰
- 關鍵業(yè)務讀寫操作全部指向主機瞧预,非關鍵業(yè)務采用讀寫分離
- 例如艺谆,對于一個用戶管理系統(tǒng)來說榨惰,注冊 + 登錄的業(yè)務讀寫操作全部訪問主機,用戶的介紹静汤、愛好琅催、等級等業(yè)務居凶,可以采用讀寫分離,因為即使用戶改了自己的自我介紹恢暖,在查詢時卻看到了自我介紹還是舊的排监,業(yè)務影響與不能登錄相比就小很多,還可以忍受
分配機制
- 將讀寫操作區(qū)分開來杰捂,然后訪問不同的數據庫服務器舆床,一般有兩種方式:程序代碼封裝和中間件封裝
- 程序代碼封裝
- 程序代碼封裝指在代碼中抽象一個數據訪問層(所以有的文章也稱這種方式為“中間層封裝”),實現(xiàn)讀寫操作分離和數據庫服務器連接的管理
- 例如嫁佳,基于 Hibernate 進行簡單封裝挨队,就可以實現(xiàn)讀寫分離,基本架構是:
-
程序代碼封裝的方式具備幾個特點:
- 實現(xiàn)簡單蒿往,而且可以根據業(yè)務做較多定制化的功能
- 每個編程語言都需要自己實現(xiàn)一次盛垦,無法通用,如果一個業(yè)務包含多個編程語言寫的多個子系統(tǒng)瓤漏,則重復開發(fā)的工作量比較大
- 故障情況下腾夯,如果主從發(fā)生切換,則可能需要所有系統(tǒng)都修改配置并重啟
- 目前開源的實現(xiàn)方案中蔬充,淘寶的 TDDL(Taobao Distributed Data Layer蝶俱,外號: 頭都大了)是比較有名的,其基本原理是一個基于集中式配置的 jdbc datasource 實現(xiàn)饥漫,具有主備榨呆、讀寫分離、動態(tài)數據庫配置等功能庸队,基本架構是:
- 中間件封裝
- 中間件封裝指的是獨立一套系統(tǒng)出來积蜻,實現(xiàn)讀寫操作分離和數據庫服務器連接的管理
- 中間件對業(yè)務服務器提供 SQL 兼容的協(xié)議,業(yè)務服務器無須自己進行讀寫分離
- 對于業(yè)務服務器來說彻消,訪問中間件和訪問數據庫沒有區(qū)別竿拆,事實上在業(yè)務服務器看來,中間件就是一個數據庫服務器宾尚。其基本架構是:
-
數據庫中間件的方式具備的特點是:
- 能夠支持多種編程語言丙笋,因為數據庫中間件對業(yè)務服務器提供的是標準 SQL 接口
- 數據庫中間件要支持完整的 SQL 語法和數據庫服務器的協(xié)議(例如,MySQL 客戶端和服務器的連接協(xié)議)央勒,實現(xiàn)比較復雜,細節(jié)特別多澳化,很容易出現(xiàn) bug崔步,需要較長的時間才能穩(wěn)定
- 數據庫中間件自己不執(zhí)行真正的讀寫操作,但所有的數據庫操作請求都要經過中間件缎谷,中間件的性能要求也很高
- 數據庫主從切換對業(yè)務服務器無感知井濒,數據庫中間件可以探測數據庫服務器的主從狀態(tài)灶似。例如,向某個測試表寫入一條數據瑞你,成功的就是主機酪惭,失敗的就是從機
-
由于數據庫中間件的復雜度要比程序代碼封裝高出一個數量級,一般情況下建議采用程序語言封裝的方式者甲,或者使用成熟的開源數據庫中間件
- 如果是大公司春感,可以投入人力去實現(xiàn)數據庫中間件,因為這個系統(tǒng)一旦做好虏缸,接入的業(yè)務系統(tǒng)越多鲫懒,節(jié)省的程序開發(fā)投入就越多,價值也越大
- 目前的開源數據庫中間件方案中刽辙,MySQL 官方先是提供了 MySQL Proxy窥岩,但 MySQL Proxy 一直沒有正式 GA,現(xiàn)在 MySQL 官方推薦 MySQL Router
- MySQL Router 的主要功能有讀寫分離宰缤、故障自動切換颂翼、負載均衡、連接池等慨灭,其基本架構如下:
奇虎 360 公司也開源了自己的數據庫中間件 Atlas朦乏,Atlas 是基于 MySQL Proxy 實現(xiàn)的
Atlas 是一個位于應用程序與 MySQL 之間中間件。在后端 DB 看來缘挑,Atlas 相當于連接它的客戶端集歇,在前端應用看來,Atlas 相當于一個 DB语淘。Atlas 作為服務端與應用程序通信诲宇,它實現(xiàn)了 MySQL 的客戶端和服務端協(xié)議,同時作為客戶端與 MySQL 通信惶翻。它對應用程序屏蔽了 DB 的細節(jié)姑蓝,同時為了降低 MySQL 負擔,它還維護了連接池
小結
本文講了讀寫分離方式的原理吕粗,以及兩個設計復雜度:復制延遲和分配機制纺荧,希望對你有所幫助