作者:菜菜
出處:https://segmentfault.com/a/1190000037571976
靈魂拷問:
- 解決數(shù)據(jù)庫讀寫瓶頸有哪些解決方案呢沸呐?
- 這些方案解決了什么問題呢烘绽?
- 這些方案有那些優(yōu)勢和劣勢呢?
分庫分表作為一種普遍的解決方案慎式,幾乎已經(jīng)成為面試者吹水的利劍,卻很少有人在意它所帶來的副作用趟径。其實分庫分表是利用了分治的思路來解決數(shù)據(jù)庫的瓶頸問題瘪吏,這種方案同時解決了并發(fā)讀和并發(fā)寫的瓶頸,利用數(shù)據(jù)分片的方式蜗巧,以堆積硬件的方式來抵抗了高流量的沖擊掌眠,當(dāng)然帶來了某些業(yè)務(wù)需要跨庫查詢,跨表join等問題幕屹,不過這些問題總能以別的解決方案來應(yīng)對蓝丙。
數(shù)據(jù)庫讀寫分離是解決數(shù)據(jù)庫性能瓶頸的另外一個方案级遭,和分庫分表方案相比較,他們有著本質(zhì)的區(qū)別渺尘。分庫分表會把數(shù)據(jù)分散在多個庫表中挫鸽,然后利用數(shù)據(jù)分片的規(guī)則來讀取和寫入數(shù)據(jù),而讀寫分離是利用“冗余”的方式來應(yīng)對大流量的沖擊鸥跟。
讀寫分離原理
讀寫分離的基本原理是將數(shù)據(jù)讀寫分散到不同的數(shù)據(jù)庫節(jié)點上丢郊,寫操作一般只發(fā)生在主節(jié)點,可以接受少量延遲的讀操作發(fā)生在從節(jié)點上
至于讀寫分離的實現(xiàn)方式:
- 多臺數(shù)據(jù)庫服務(wù)器組件成集群医咨,并配置主從關(guān)系
- 主節(jié)點負責(zé)讀寫操作枫匾,從節(jié)點只負責(zé)讀操作
- 主節(jié)點通過數(shù)據(jù)復(fù)制機制,把數(shù)據(jù)從主節(jié)點同步到所有的從節(jié)點
- 業(yè)務(wù)方利用程序或者中間件把寫操作發(fā)送給主節(jié)點拟淮,將讀操作發(fā)送給從節(jié)點
讀寫分離優(yōu)勢
一般的系統(tǒng)都會滿足28原則干茉,既:80%的操作是讀操作,20%的操作是寫操作惩歉。
系統(tǒng)的讀操作占比越大等脂,讀寫分離的優(yōu)勢就越發(fā)明顯,因為讀操作可以通過簡單的增加數(shù)據(jù)庫從節(jié)點來解決撑蚌,當(dāng)然從節(jié)點的增加并不是毫無限制上遥,當(dāng)從節(jié)點到達一定數(shù)量的時候,必然會影響主從同步的效率争涌,會降低主節(jié)點的性能粉楚,這個時候需要考慮一致性和可用性的平衡問題了。
另外一點亮垫,在很多業(yè)務(wù)中都會有一定的數(shù)據(jù)統(tǒng)計需求模软,單機數(shù)據(jù)庫的時候,這些統(tǒng)計需求執(zhí)行的sql和業(yè)務(wù)sql混合在一起饮潦,在一定程度上會影響正常業(yè)務(wù)的運行燃异,尤其是那些數(shù)據(jù)量比較大的業(yè)務(wù)場景。在做了讀寫分離的策略之后继蜡,統(tǒng)計業(yè)務(wù)完全可以獨占一個從庫來進行統(tǒng)計回俐,就算是比較耗時的操作,也不會影響正常的業(yè)務(wù)運行稀并。
數(shù)據(jù)庫的讀寫分離方案在所有讀操作場景中仅颇,發(fā)揮了最大優(yōu)勢
讀寫分離劣勢
數(shù)據(jù)庫讀寫分離有一個很多系統(tǒng)都會遇到的問題,那就是有些業(yè)務(wù)在寫操作成功之后需要實時的讀取到數(shù)據(jù)碘举,可是數(shù)據(jù)從主節(jié)點同步到從節(jié)點是有一定時間延遲的忘瓦,所以很多情況下業(yè)務(wù)方在從節(jié)點并不能實時的讀取到正確的數(shù)據(jù),這種業(yè)務(wù)場景其實就是主節(jié)點也需要提供讀操作的典型場景引颈,當(dāng)然如果系統(tǒng)架設(shè)的有緩存模塊耕皮,在主節(jié)點寫操作成功之后可以同步更新緩存境蜕,以達到業(yè)務(wù)需要實時數(shù)據(jù)的要求。
路由機制
讀寫分離在寫操作上有著嚴格的要求凌停,寫操作必須發(fā)生在主節(jié)點上汽摹,因為讀寫分離是基于中心化的思想來建立的集群,中心化的思想要求主節(jié)點上的數(shù)據(jù)必須是最新且最全的苦锨。這就要求調(diào)用方必須要區(qū)分出主節(jié)點才可以。
代碼封裝
用程序代碼封裝讀寫分離邏輯需要在代碼中抽象出一個數(shù)據(jù)訪問層趴泌,在這一層中實現(xiàn)操作分離以及數(shù)據(jù)庫的連接管理等舟舒。
用代碼封裝讀寫分離邏輯在落地上并非易事,需要經(jīng)過很長時間的測試才可以上生產(chǎn)環(huán)境嗜憔。如果公司內(nèi)部存在多個語言的開發(fā)團隊秃励,每個語言可能都需要實現(xiàn)一次,開發(fā)量還是比較大的吉捶。但是在針對不同的業(yè)務(wù)中夺鲜,可以做到定制化的需求,在落地過程中還需要考慮如果主從發(fā)生切換呐舔,代碼中必須要有類似選舉的過程币励。
數(shù)據(jù)庫中間件
數(shù)據(jù)庫中間件是指基于數(shù)據(jù)庫提供的SQL協(xié)議來開發(fā)的一套和具體業(yè)務(wù)無關(guān)的系統(tǒng),它的作用也是實現(xiàn)操作分離和數(shù)據(jù)庫的連接管理等珊拼,它同樣也是對讀寫分離的一個抽象層食呻,但是這個抽象層是基于數(shù)據(jù)庫協(xié)議的,對于業(yè)務(wù)的使用方來說澎现,就像訪問單個數(shù)據(jù)庫一樣方便仅胞。
同步延遲
任何分布式的系統(tǒng)都逃不過一致性的問題。數(shù)據(jù)庫的主從架構(gòu)也是一樣剑辫,發(fā)生在主節(jié)點的操作需要同步給每個從庫干旧。像MySQL的主從復(fù)制是依賴于binlog的,主從復(fù)制就是將binlog中的數(shù)據(jù)從主庫復(fù)制到從庫上妹蔽,一般這個過程都會采用異步的方式椎眯,因為在網(wǎng)絡(luò)延遲的情況下,如果采用同步方式會大大降低主庫的可用性讹开。
在binlog的復(fù)制過程中盅视,極低的概率會發(fā)生binlog還沒有來得及刷新到磁盤就出現(xiàn)磁盤壞掉或者down機的情況,最終的效果就是主從數(shù)據(jù)的不一致旦万,但是這種不可抗拒的因素闹击,一般是可以容忍的。
還有一種現(xiàn)象成艘,一般數(shù)據(jù)從主節(jié)點復(fù)制到從節(jié)點會開啟單線程模式赏半,如果主庫產(chǎn)生新數(shù)據(jù)的速度大于同步的速度贺归,那有可能會進一步加大主從同步的延遲時間,這個是否可以考慮開啟多線程或者利用緩存模塊來屏蔽同步延遲的問題呢断箫?
主備方案
說到數(shù)據(jù)庫主從的架構(gòu)部署方式拂酣,還有一種類似的方案:主備。主備是利用冗余一個節(jié)點來做備用節(jié)點仲义,但是這個節(jié)點在主節(jié)點正常運行的情況下婶熬,不會對外提供服務(wù),做了一個真正的“備胎”埃撵。當(dāng)主節(jié)點掛掉赵颅,備用節(jié)點會代替主節(jié)點的位置,并成為主節(jié)點開始對外提供服務(wù)暂刘。
主備方式可以利用簡單的類似keepalive機制來實現(xiàn)自動化饺谬,理論上不需要進行選舉操作。利用主備方式來實現(xiàn)數(shù)據(jù)庫高可用有哪些特點呢谣拣?
- 可用性是利用keepalive機制來保證的募寨,這個切換過程對業(yè)務(wù)是透明的,業(yè)務(wù)方無需修改任何代碼
- 讀寫都在主庫上進行森缠,很容易產(chǎn)生單點的瓶頸問題拔鹰,由于沒有其他節(jié)點的數(shù)據(jù)同步過程,所以數(shù)據(jù)可以保證一致性
- 主備架構(gòu)中贵涵,備庫只是單純的備份格郁,整體的資源利用率50%,因為備庫一直在被閑置
- 擴展性比較差独悴,無法做到橫向擴展例书,但是可以利用分庫分表來解決擴展性問題
一主一備或者一主多備方案在資源的利用率上很低,所以后來出現(xiàn)了多主的架構(gòu)刻炒,多主架構(gòu)是指决采,會存在多個主庫,每個主庫都提供讀寫功能坟奥,這就涉及到多個主庫之間數(shù)據(jù)同步的方式树瞭,雖然性能上要比一主要高,但是數(shù)據(jù)一致性上很難搞爱谁。所以很多互聯(lián)網(wǎng)公司并不推薦使用這種方案晒喷。
寫在最后
數(shù)據(jù)庫的擴展由于其屬于有狀態(tài)的范疇,所以比無狀態(tài)的網(wǎng)站或者服務(wù)要困難很多》玫校現(xiàn)在主流的落地方案也都是基于“分”的策略凉敲,分庫分表方案和主從讀寫分離方案是兩種最常用的擴展方式,在很多情況下,二者是結(jié)合起來使用的爷抓,即:在分庫分表的情況下势决,每個節(jié)點采用主從讀寫分離的方式,這也是目前比較主流的方式了蓝撇。