高性能數(shù)據(jù)庫(kù)集群的第一種方式是“讀寫(xiě)分離”虱痕,其本質(zhì)是將訪問(wèn)壓力分散到集群中的多個(gè)節(jié)點(diǎn)惩阶,但是沒(méi)有分散存儲(chǔ)壓力;第二種方式是“分庫(kù)分表”钾埂,既可以分散訪問(wèn)壓力河闰,又可以分散存儲(chǔ)壓力。先來(lái)看看“讀寫(xiě)分離”褥紫,下一期我再介紹“分庫(kù)分表”姜性。
讀寫(xiě)分離原理
讀寫(xiě)分離的基本原理是將數(shù)據(jù)庫(kù)讀寫(xiě)操作分散到不同的節(jié)點(diǎn)上,下面是其基本架構(gòu)圖髓考。
讀寫(xiě)分離的基本實(shí)現(xiàn)是:
數(shù)據(jù)庫(kù)服務(wù)器搭建主從集群部念,一主一從、一主多從都可以。
數(shù)據(jù)庫(kù)主機(jī)負(fù)責(zé)讀寫(xiě)操作儡炼,從機(jī)只負(fù)責(zé)讀操作妓湘。
數(shù)據(jù)庫(kù)主機(jī)通過(guò)復(fù)制將數(shù)據(jù)同步到從機(jī),每臺(tái)數(shù)據(jù)庫(kù)服務(wù)器都存儲(chǔ)了所有的業(yè)務(wù)數(shù)據(jù)乌询。
業(yè)務(wù)服務(wù)器將寫(xiě)操作發(fā)給數(shù)據(jù)庫(kù)主機(jī)多柑,將讀操作發(fā)給數(shù)據(jù)庫(kù)從機(jī)。
需要注意的是楣责,這里用的是“主從集群”竣灌,而不是“主備集群”「阳铮“從機(jī)”的“從”可以理解為“仆從”初嘹,仆從是要幫主人干活的,“從機(jī)”是需要提供讀數(shù)據(jù)的功能的沮趣;而“備機(jī)”一般被認(rèn)為僅僅提供備份功能屯烦,不提供訪問(wèn)功能。所以使用“主從”還是“主備”房铭,是要看場(chǎng)景的驻龟,這兩個(gè)詞并不是完全等同的。
讀寫(xiě)分離的實(shí)現(xiàn)邏輯并不復(fù)雜缸匪,但有兩個(gè)細(xì)節(jié)點(diǎn)將引入設(shè)計(jì)復(fù)雜度:主從復(fù)制延遲和分配機(jī)制翁狐。
復(fù)制延遲
以 MySQL 為例,主從復(fù)制延遲可能達(dá)到 1 秒凌蔬,如果有大量數(shù)據(jù)同步露懒,延遲 1 分鐘也是有可能的。主從復(fù)制延遲會(huì)帶來(lái)一個(gè)問(wèn)題:如果業(yè)務(wù)服務(wù)器將數(shù)據(jù)寫(xiě)入到數(shù)據(jù)庫(kù)主服務(wù)器后立刻(1 秒內(nèi))進(jìn)行讀取砂心,此時(shí)讀操作訪問(wèn)的是從機(jī)懈词,主機(jī)還沒(méi)有將數(shù)據(jù)復(fù)制過(guò)來(lái),到從機(jī)讀取數(shù)據(jù)是讀不到最新數(shù)據(jù)的辩诞,業(yè)務(wù)上就可能出現(xiàn)問(wèn)題坎弯。例如,用戶(hù)剛注冊(cè)完后立刻登錄译暂,業(yè)務(wù)服務(wù)器會(huì)提示他“你還沒(méi)有注冊(cè)”抠忘,而用戶(hù)明明剛才已經(jīng)注冊(cè)成功了。
解決主從復(fù)制延遲有幾種常見(jiàn)的方法:
1. 寫(xiě)操作后的讀操作指定發(fā)給數(shù)據(jù)庫(kù)主服務(wù)器
例如秧秉,注冊(cè)賬號(hào)完成后褐桌,登錄時(shí)讀取賬號(hào)的讀操作也發(fā)給數(shù)據(jù)庫(kù)主服務(wù)器。這種方式和業(yè)務(wù)強(qiáng)綁定象迎,對(duì)業(yè)務(wù)的侵入和影響較大荧嵌,如果哪個(gè)新來(lái)的程序員不知道這樣寫(xiě)代碼呛踊,就會(huì)導(dǎo)致一個(gè) bug。
2. 讀從機(jī)失敗后再讀一次主機(jī)
這就是通常所說(shuō)的“二次讀取”啦撮,二次讀取和業(yè)務(wù)無(wú)綁定谭网,只需要對(duì)底層數(shù)據(jù)庫(kù)訪問(wèn)的 API 進(jìn)行封裝即可,實(shí)現(xiàn)代價(jià)較小赃春,不足之處在于如果有很多二次讀取愉择,將大大增加主機(jī)的讀操作壓力。例如织中,黑客暴力破解賬號(hào)锥涕,會(huì)導(dǎo)致大量的二次讀取操作,主機(jī)可能頂不住讀操作的壓力從而崩潰狭吼。
3. 關(guān)鍵業(yè)務(wù)讀寫(xiě)操作全部指向主機(jī)层坠,非關(guān)鍵業(yè)務(wù)采用讀寫(xiě)分離
例如,對(duì)于一個(gè)用戶(hù)管理系統(tǒng)來(lái)說(shuō)刁笙,注冊(cè) + 登錄的業(yè)務(wù)讀寫(xiě)操作全部訪問(wèn)主機(jī)破花,用戶(hù)的介紹、愛(ài)好疲吸、等級(jí)等業(yè)務(wù)座每,可以采用讀寫(xiě)分離,因?yàn)榧词褂脩?hù)改了自己的自我介紹摘悴,在查詢(xún)時(shí)卻看到了自我介紹還是舊的峭梳,業(yè)務(wù)影響與不能登錄相比就小很多,還可以忍受烦租。
分配機(jī)制
將讀寫(xiě)操作區(qū)分開(kāi)來(lái)延赌,然后訪問(wèn)不同的數(shù)據(jù)庫(kù)服務(wù)器,一般有兩種方式:程序代碼封裝和中間件封裝叉橱。
1. 程序代碼封裝
程序代碼封裝指在代碼中抽象一個(gè)數(shù)據(jù)訪問(wèn)層(所以有的文章也稱(chēng)這種方式為“中間層封裝”),實(shí)現(xiàn)讀寫(xiě)操作分離和數(shù)據(jù)庫(kù)服務(wù)器連接的管理者蠕。例如窃祝,基于 Hibernate 進(jìn)行簡(jiǎn)單封裝,就可以實(shí)現(xiàn)讀寫(xiě)分離踱侣,基本架構(gòu)是:
程序代碼封裝的方式具備幾個(gè)特點(diǎn):
實(shí)現(xiàn)簡(jiǎn)單粪小,而且可以根據(jù)業(yè)務(wù)做較多定制化的功能。
每個(gè)編程語(yǔ)言都需要自己實(shí)現(xiàn)一次抡句,無(wú)法通用探膊,如果一個(gè)業(yè)務(wù)包含多個(gè)編程語(yǔ)言寫(xiě)的多個(gè)子系統(tǒng),則重復(fù)開(kāi)發(fā)的工作量比較大待榔。
故障情況下逞壁,如果主從發(fā)生切換流济,則可能需要所有系統(tǒng)都修改配置并重啟。
目前開(kāi)源的實(shí)現(xiàn)方案中腌闯,淘寶的 TDDL(Taobao Distributed Data Layer绳瘟,外號(hào): 頭都大了)是比較有名的。它是一個(gè)通用數(shù)據(jù)訪問(wèn)層姿骏,所有功能封裝在 jar 包中提供給業(yè)務(wù)代碼調(diào)用糖声。其基本原理是一個(gè)基于集中式配置的 jdbc datasource 實(shí)現(xiàn),具有主備分瘦、讀寫(xiě)分離蘸泻、動(dòng)態(tài)數(shù)據(jù)庫(kù)配置等功能,基本架構(gòu)是:
(http://1.im.guokr.com/0Y5YjfjQ8eGOzeskpen2mlNIYA_b7DBLbGT0YHyUiLFZAgAAgwEAAFBO.png)
2. 中間件封裝
中間件封裝指的是獨(dú)立一套系統(tǒng)出來(lái)嘲玫,實(shí)現(xiàn)讀寫(xiě)操作分離和數(shù)據(jù)庫(kù)服務(wù)器連接的管理悦施。中間件對(duì)業(yè)務(wù)服務(wù)器提供 SQL 兼容的協(xié)議,業(yè)務(wù)服務(wù)器無(wú)須自己進(jìn)行讀寫(xiě)分離趁冈。對(duì)于業(yè)務(wù)服務(wù)器來(lái)說(shuō)歼争,訪問(wèn)中間件和訪問(wèn)數(shù)據(jù)庫(kù)沒(méi)有區(qū)別,事實(shí)上在業(yè)務(wù)服務(wù)器看來(lái)渗勘,中間件就是一個(gè)數(shù)據(jù)庫(kù)服務(wù)器沐绒。其基本架構(gòu)是:
數(shù)據(jù)庫(kù)中間件的方式具備的特點(diǎn)是:
能夠支持多種編程語(yǔ)言,因?yàn)閿?shù)據(jù)庫(kù)中間件對(duì)業(yè)務(wù)服務(wù)器提供的是標(biāo)準(zhǔn) SQL 接口旺坠。
數(shù)據(jù)庫(kù)中間件要支持完整的 SQL 語(yǔ)法和數(shù)據(jù)庫(kù)服務(wù)器的協(xié)議(例如乔遮,MySQL 客戶(hù)端和服務(wù)器的連接協(xié)議),實(shí)現(xiàn)比較復(fù)雜取刃,細(xì)節(jié)特別多蹋肮,很容易出現(xiàn) bug,需要較長(zhǎng)的時(shí)間才能穩(wěn)定璧疗。
數(shù)據(jù)庫(kù)中間件自己不執(zhí)行真正的讀寫(xiě)操作坯辩,但所有的數(shù)據(jù)庫(kù)操作請(qǐng)求都要經(jīng)過(guò)中間件,中間件的性能要求也很高崩侠。
數(shù)據(jù)庫(kù)主從切換對(duì)業(yè)務(wù)服務(wù)器無(wú)感知漆魔,數(shù)據(jù)庫(kù)中間件可以探測(cè)數(shù)據(jù)庫(kù)服務(wù)器的主從狀態(tài)。例如却音,向某個(gè)測(cè)試表寫(xiě)入一條數(shù)據(jù)改抡,成功的就是主機(jī),失敗的就是從機(jī)系瓢。
由于數(shù)據(jù)庫(kù)中間件的復(fù)雜度要比程序代碼封裝高出一個(gè)數(shù)量級(jí)阿纤,一般情況下建議采用程序語(yǔ)言封裝的方式,或者使用成熟的開(kāi)源數(shù)據(jù)庫(kù)中間件夷陋。如果是大公司欠拾,可以投入人力去實(shí)現(xiàn)數(shù)據(jù)庫(kù)中間件胰锌,因?yàn)檫@個(gè)系統(tǒng)一旦做好,接入的業(yè)務(wù)系統(tǒng)越多清蚀,節(jié)省的程序開(kāi)發(fā)投入就越多匕荸,價(jià)值也越大。
目前的開(kāi)源數(shù)據(jù)庫(kù)中間件方案中枷邪,MySQL 官方先是提供了 MySQL Proxy榛搔,但 MySQL Proxy 一直沒(méi)有正式 GA,現(xiàn)在 MySQL 官方推薦 MySQL Router东揣。MySQL Router 的主要功能有讀寫(xiě)分離践惑、故障自動(dòng)切換、負(fù)載均衡嘶卧、連接池等尔觉,其基本架構(gòu)如下:
(https://dev.mysql.com/doc/mysql-router/2.1/en/images/mysql-router-positioning.png)
奇虎 360 公司也開(kāi)源了自己的數(shù)據(jù)庫(kù)中間件 Atlas,Atlas 是基于 MySQL Proxy 實(shí)現(xiàn)的芥吟,基本架構(gòu)如下:
以下是官方介紹侦铜,更多內(nèi)容你可以參考這里。
Atlas 是一個(gè)位于應(yīng)用程序與 MySQL 之間中間件钟鸵。在后端 DB 看來(lái)钉稍,Atlas 相當(dāng)于連接它的客戶(hù)端,在前端應(yīng)用看來(lái)棺耍,Atlas 相當(dāng)于一個(gè) DB贡未。Atlas 作為服務(wù)端與應(yīng)用程序通信,它實(shí)現(xiàn)了 MySQL 的客戶(hù)端和服務(wù)端協(xié)議蒙袍,同時(shí)作為客戶(hù)端與 MySQL 通信俊卤。它對(duì)應(yīng)用程序屏蔽了 DB 的細(xì)節(jié),同時(shí)為了降低 MySQL 負(fù)擔(dān)害幅,它還維護(hù)了連接池消恍。
小結(jié)
數(shù)據(jù)庫(kù)讀寫(xiě)分離一般應(yīng)用于什么場(chǎng)景?能支撐多大的業(yè)務(wù)規(guī)模以现?
評(píng)論1
我們做網(wǎng)銀系統(tǒng)哺哼,用redis存了一些不太重要的數(shù)據(jù),比如數(shù)據(jù)字典信息叼风,作為緩存。但是不太敢把用戶(hù)權(quán)限棍苹,交易數(shù)據(jù)等重要信息存在緩存里无宿,因?yàn)?b>redis并不保證事務(wù),我們擔(dān)心一旦緩存服務(wù)器宕機(jī)或者失敗會(huì)影響銀行業(yè)務(wù)枢里。所以緩存的作用也不是很大孽鸡,還是把大部分讀數(shù)據(jù)的壓力放到了數(shù)據(jù)庫(kù)上蹂午,您說(shuō)我們這種擔(dān)心有必要嗎?如果單庫(kù)后續(xù)扛不住壓力彬碱,是否讀寫(xiě)分離比加緩存更好一些豆胸?
交易型業(yè)務(wù)緩存應(yīng)用不多,緩存一般總在查詢(xún)類(lèi)業(yè)務(wù)上巷疼,你們的擔(dān)心有一定必要
評(píng)論2
適合:讀多寫(xiě)少
不適用的情況:1如果并發(fā)寫(xiě)入特別高晚胡,單機(jī)寫(xiě)入無(wú)法支撐,就不適合這種模式嚼沿。
2 通過(guò)緩存技術(shù)或者程序優(yōu)化能夠滿(mǎn)足要求
同步速度主要受網(wǎng)絡(luò)延遲影響估盘,和硬件關(guān)系不大,而且線(xiàn)上配置最好一樣骡尽,否則出問(wèn)題不好排查