程序員修神之路--略懂?dāng)?shù)據(jù)庫(kù)集群讀寫分離而已
“靈魂拷問:
- 解決數(shù)據(jù)庫(kù)讀寫瓶頸有哪些解決方案呢?
- 這些方案解決了什么問題呢?
- 這些方案有那些優(yōu)勢(shì)和劣勢(shì)呢?
一個(gè)可以抵抗高并發(fā)流量系統(tǒng)的背后必定有一個(gè)高性能的數(shù)據(jù)庫(kù)集群,就像每一個(gè)成功的男人背后總有一個(gè)強(qiáng)勢(shì)的女人一樣。數(shù)據(jù)庫(kù)集群在部署模式上屬于分布式,但是CAP原則卻不適用于分布式數(shù)據(jù)庫(kù)。
分庫(kù)分表作為一種普遍的解決方案,幾乎已經(jīng)成為面試者吹水的利劍,卻很少有人在意它所帶來的副作用。其實(shí)分庫(kù)分表是利用了分治的思路來解決數(shù)據(jù)庫(kù)的瓶頸問題,這種方案同時(shí)解決了并發(fā)讀和并發(fā)寫的瓶頸,利用數(shù)據(jù)分片的方式,以堆積硬件的方式來抵抗了高流量的沖擊,當(dāng)然帶來了某些業(yè)務(wù)需要跨庫(kù)查詢,跨表join等問題,不過這些問題總能以別的解決方案來應(yīng)對(duì)。
數(shù)據(jù)庫(kù)讀寫分離是解決數(shù)據(jù)庫(kù)性能瓶頸的另外一個(gè)方案,和分庫(kù)分表方案相比較,他們有著本質(zhì)的區(qū)別。分庫(kù)分表會(huì)把數(shù)據(jù)分散在多個(gè)庫(kù)表中,然后利用數(shù)據(jù)分片的規(guī)則來讀取和寫入數(shù)據(jù),而讀寫分離是利用“冗余”的方式來應(yīng)對(duì)大流量的沖擊。
讀寫分離原理
讀寫分離的基本原理是將數(shù)據(jù)讀寫分散到不同的數(shù)據(jù)庫(kù)節(jié)點(diǎn)上,寫操作一般只發(fā)生在主節(jié)點(diǎn),可以接受少量延遲的讀操作發(fā)生在從節(jié)點(diǎn)上
image
至于讀寫分離的實(shí)現(xiàn)方式:
- 多臺(tái)數(shù)據(jù)庫(kù)服務(wù)器組件成集群,并配置主從關(guān)系
- 主節(jié)點(diǎn)負(fù)責(zé)讀寫操作,從節(jié)點(diǎn)只負(fù)責(zé)讀操作
- 主節(jié)點(diǎn)通過數(shù)據(jù)復(fù)制機(jī)制,把數(shù)據(jù)從主節(jié)點(diǎn)同步到所有的從節(jié)點(diǎn)
- 業(yè)務(wù)方利用程序或者中間件把寫操作發(fā)送給主節(jié)點(diǎn),將讀操作發(fā)送給從節(jié)點(diǎn)
讀寫分離優(yōu)勢(shì)
一般的系統(tǒng)都會(huì)滿足28原則,既:80%的操作是讀操作,20%的操作是寫操作。系統(tǒng)的讀操作占比越大,讀寫分離的優(yōu)勢(shì)就越發(fā)明顯,因?yàn)樽x操作可以通過簡(jiǎn)單的增加數(shù)據(jù)庫(kù)從節(jié)點(diǎn)來解決,當(dāng)然從節(jié)點(diǎn)的增加并不是毫無限制,當(dāng)從節(jié)點(diǎn)到達(dá)一定數(shù)量的時(shí)候,必然會(huì)影響主從同步的效率,會(huì)降低主節(jié)點(diǎn)的性能,這個(gè)時(shí)候需要考慮一致性和可用性的平衡問題了。
另外一點(diǎn),在很多業(yè)務(wù)中都會(huì)有一定的數(shù)據(jù)統(tǒng)計(jì)需求,單機(jī)數(shù)據(jù)庫(kù)的時(shí)候,這些統(tǒng)計(jì)需求執(zhí)行的sql和業(yè)務(wù)sql混合在一起,在一定程度上會(huì)影響正常業(yè)務(wù)的運(yùn)行,尤其是那些數(shù)據(jù)量比較大的業(yè)務(wù)場(chǎng)景。在做了讀寫分離的策略之后,統(tǒng)計(jì)業(yè)務(wù)完全可以獨(dú)占一個(gè)從庫(kù)來進(jìn)行統(tǒng)計(jì),就算是比較耗時(shí)的操作,也不會(huì)影響正常的業(yè)務(wù)運(yùn)行。
數(shù)據(jù)庫(kù)的讀寫分離方案在所有讀操作場(chǎng)景中,發(fā)揮了最大優(yōu)勢(shì)
讀寫分離劣勢(shì)
數(shù)據(jù)庫(kù)讀寫分離有一個(gè)很多系統(tǒng)都會(huì)遇到的問題,那就是有些業(yè)務(wù)在寫操作成功之后需要實(shí)時(shí)的讀取到數(shù)據(jù),可是數(shù)據(jù)從主節(jié)點(diǎn)同步到從節(jié)點(diǎn)是有一定時(shí)間延遲的,所以很多情況下業(yè)務(wù)方在從節(jié)點(diǎn)并不能實(shí)時(shí)的讀取到正確的數(shù)據(jù),這種業(yè)務(wù)場(chǎng)景其實(shí)就是主節(jié)點(diǎn)也需要提供讀操作的典型場(chǎng)景,當(dāng)然如果系統(tǒng)架設(shè)的有緩存模塊,在主節(jié)點(diǎn)寫操作成功之后可以同步更新緩存,以達(dá)到業(yè)務(wù)需要實(shí)時(shí)數(shù)據(jù)的要求。
路由機(jī)制
讀寫分離在寫操作上有著嚴(yán)格的要求,寫操作必須發(fā)生在主節(jié)點(diǎn)上,因?yàn)樽x寫分離是基于中心化的思想來建立的集群,中心化的思想要求主節(jié)點(diǎn)上的數(shù)據(jù)必須是最新且最全的。這就要求調(diào)用方必須要區(qū)分出主節(jié)點(diǎn)才可以。
- 代碼封裝
用程序代碼封裝讀寫分離邏輯需要在代碼中抽象出一個(gè)數(shù)據(jù)訪問層,在這一層中實(shí)現(xiàn)操作分離以及數(shù)據(jù)庫(kù)的連接管理等。

image
用代碼封裝讀寫分離邏輯在落地上并非易事,需要經(jīng)過很長(zhǎng)時(shí)間的測(cè)試才可以上生產(chǎn)環(huán)境。如果公司內(nèi)部存在多個(gè)語(yǔ)言的開發(fā)團(tuán)隊(duì),每個(gè)語(yǔ)言可能都需要實(shí)現(xiàn)一次,開發(fā)量還是比較大的。但是在針對(duì)不同的業(yè)務(wù)中,可以做到定制化的需求,在落地過程中還需要考慮如果主從發(fā)生切換,代碼中必須要有類似選舉的過程。
- 數(shù)據(jù)庫(kù)中間件
數(shù)據(jù)庫(kù)中間件是指基于數(shù)據(jù)庫(kù)提供的SQL協(xié)議來開發(fā)的一套和具體業(yè)務(wù)無關(guān)的系統(tǒng),它的作用也是實(shí)現(xiàn)操作分離和數(shù)據(jù)庫(kù)的連接管理等,它同樣也是對(duì)讀寫分離的一個(gè)抽象層,但是這個(gè)抽象層是基于數(shù)據(jù)庫(kù)協(xié)議的,對(duì)于業(yè)務(wù)的使用方來說,就像訪問單個(gè)數(shù)據(jù)庫(kù)一樣方便。

image
同步延遲
任何分布式的系統(tǒng)都逃不過一致性的問題。數(shù)據(jù)庫(kù)的主從架構(gòu)也是一樣,發(fā)生在主節(jié)點(diǎn)的操作需要同步給每個(gè)從庫(kù)。像MySQL的主從復(fù)制是依賴于binlog的,主從復(fù)制就是將binlog中的數(shù)據(jù)從主庫(kù)復(fù)制到從庫(kù)上,一般這個(gè)過程都會(huì)采用異步的方式,因?yàn)樵诰W(wǎng)絡(luò)延遲的情況下,如果采用同步方式會(huì)大大降低主庫(kù)的可用性。
在binlog的復(fù)制過程中,極低的概率會(huì)發(fā)生binlog還沒有來得及刷新到磁盤就出現(xiàn)磁盤壞掉或者down機(jī)的情況,最終的效果就是主從數(shù)據(jù)的不一致,但是這種不可抗拒的因素,一般是可以容忍的。
還有一種現(xiàn)象,一般數(shù)據(jù)從主節(jié)點(diǎn)復(fù)制到從節(jié)點(diǎn)會(huì)開啟單線程模式,如果主庫(kù)產(chǎn)生新數(shù)據(jù)的速度大于同步的速度,那有可能會(huì)進(jìn)一步加大主從同步的延遲時(shí)間,這個(gè)是否可以考慮開啟多線程或者利用緩存模塊來屏蔽同步延遲的問題呢?
主備方案
說到數(shù)據(jù)庫(kù)主從的架構(gòu)部署方式,還有一種類似的方案:主備。主備是利用冗余一個(gè)節(jié)點(diǎn)來做備用節(jié)點(diǎn),但是這個(gè)節(jié)點(diǎn)在主節(jié)點(diǎn)正常運(yùn)行的情況下,不會(huì)對(duì)外提供服務(wù),做了一個(gè)真正的“備胎”。當(dāng)主節(jié)點(diǎn)掛掉,備用節(jié)點(diǎn)會(huì)代替主節(jié)點(diǎn)的位置,并成為主節(jié)點(diǎn)開始對(duì)外提供服務(wù)。
主備方式可以利用簡(jiǎn)單的類似keepalive機(jī)制來實(shí)現(xiàn)自動(dòng)化,理論上不需要進(jìn)行選舉操作。利用主備方式來實(shí)現(xiàn)數(shù)據(jù)庫(kù)高可用有哪些特點(diǎn)呢?
- 可用性是利用keepalive機(jī)制來保證的,這個(gè)切換過程對(duì)業(yè)務(wù)是透明的,業(yè)務(wù)方無需修改任何代碼
- 讀寫都在主庫(kù)上進(jìn)行,很容易產(chǎn)生單點(diǎn)的瓶頸問題,由于沒有其他節(jié)點(diǎn)的數(shù)據(jù)同步過程,所以數(shù)據(jù)可以保證一致性
- 主備架構(gòu)中,備庫(kù)只是單純的備份,整體的資源利用率50%,因?yàn)閭鋷?kù)一直在被閑置
- 擴(kuò)展性比較差,無法做到橫向擴(kuò)展,但是可以利用分庫(kù)分表來解決擴(kuò)展性問題
一主一備或者一主多備方案在資源的利用率上很低,所以后來出現(xiàn)了多主的架構(gòu),多主架構(gòu)是指,會(huì)存在多個(gè)主庫(kù),每個(gè)主庫(kù)都提供讀寫功能,這就涉及到多個(gè)主庫(kù)之間數(shù)據(jù)同步的方式,雖然性能上要比一主要高,但是數(shù)據(jù)一致性上很難搞。所以很多互聯(lián)網(wǎng)公司并不推薦使用這種方案。
寫在最后
數(shù)據(jù)庫(kù)的擴(kuò)展由于其屬于有狀態(tài)的范疇,所以比無狀態(tài)的網(wǎng)站或者服務(wù)要困難很多。現(xiàn)在主流的落地方案也都是基于“分”的策略,分庫(kù)分表方案和主從讀寫分離方案是兩種最常用的擴(kuò)展方式,在很多情況下,二者是結(jié)合起來使用的,即:在分庫(kù)分表的情況下,每個(gè)節(jié)點(diǎn)采用主從讀寫分離的方式,這也是目前比較主流的方式了。
本文轉(zhuǎn)載自微信公眾號(hào)「架構(gòu)師修行之路」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系架構(gòu)師修行之路公眾號(hào)。