讀服務(wù)+寫(xiě)服務(wù)分離架構(gòu),我堅(jiān)決反對(duì)!
系統(tǒng)分層架構(gòu)有一個(gè)迭代和演進(jìn)的過(guò)程,早期,系統(tǒng)二層架構(gòu)如下:
(1)上游是業(yè)務(wù)應(yīng)用;
(2)下游是數(shù)據(jù)庫(kù);
隨著架構(gòu)的演進(jìn),可能要抽取出微服務(wù),系統(tǒng)三層架構(gòu)如下:
(1)上游仍是業(yè)務(wù)應(yīng)用;
(2)中間是微服務(wù)層,提供RPC接口;
(3)下游是數(shù)據(jù)庫(kù);
大家都知道,數(shù)據(jù)庫(kù)可以讀寫(xiě)分離,為了職責(zé)更清新,架構(gòu)設(shè)計(jì)上,服務(wù)能否讀寫(xiě)分離呢?
如上圖,服務(wù)化讀寫(xiě)分離之后:
(1)業(yè)務(wù)方通過(guò)RPC分別調(diào)用讀服務(wù)和寫(xiě)服務(wù);
(2)服務(wù)層分為讀服務(wù)與寫(xiě)服務(wù);
(3)底層是高可用的數(shù)據(jù)庫(kù)集群;
當(dāng)然,也有可能讀服務(wù)與寫(xiě)服務(wù)讀寫(xiě)的是不同的數(shù)據(jù)庫(kù),如上圖:
(1)寫(xiě)服務(wù)訪問(wèn)寫(xiě)庫(kù);
(2)讀服務(wù)訪問(wèn)讀庫(kù);
寫(xiě)庫(kù)與讀庫(kù)是一個(gè)主從同步的集群。
那么,問(wèn)題來(lái)了:
(1)你遇到過(guò)這種讀服務(wù)+寫(xiě)服務(wù)分離的架構(gòu)設(shè)計(jì)么?
(2)這種架構(gòu)設(shè)計(jì)好還是不好,為什么?
樓主支持這種讀寫(xiě)服務(wù)分離的架構(gòu)設(shè)計(jì)么?
先說(shuō)結(jié)論,我旗幟鮮明的反對(duì)服務(wù)區(qū)分讀寫(xiě)分離。
為什么反對(duì)呢?
大大小小的理由,有這么五點(diǎn)。
第一點(diǎn):對(duì)于調(diào)用方而言,調(diào)用同一個(gè)基礎(chǔ)服務(wù),要訪問(wèn)其RPC接口,究竟調(diào)用讀服務(wù),還是寫(xiě)服務(wù),容易困惑。
第二點(diǎn):對(duì)于同一個(gè)基礎(chǔ)服務(wù),服務(wù)數(shù)量翻倍了,運(yùn)維更加復(fù)雜。
畫(huà)外音:總的來(lái)說(shuō),上面兩點(diǎn)還可以忍。
第三點(diǎn):一般來(lái)說(shuō),服務(wù)拆分,是按照“子業(yè)務(wù)”維度進(jìn)行拆分,而不是按照“讀寫(xiě)”維度進(jìn)行拆分,這是模塊化設(shè)計(jì)的基本準(zhǔn)則。
畫(huà)外音:這一點(diǎn),是原則性問(wèn)題。
第四點(diǎn):完全打破了“服務(wù)化數(shù)據(jù)庫(kù)私有”的微服務(wù)初衷。
畫(huà)外音:數(shù)據(jù)訪問(wèn),應(yīng)該收口。
兩個(gè)服務(wù)因?yàn)橥环輸?shù)據(jù)庫(kù)資源訪問(wèn)而耦合在一起,當(dāng)數(shù)據(jù)庫(kù)資源發(fā)生變化的時(shí)候(例如:ip變化,域名變化,表結(jié)構(gòu)變化,水平切分變化等),有兩個(gè)依賴點(diǎn)需要修改。
而好的設(shè)計(jì),有變化產(chǎn)生時(shí),只有一個(gè)需要修改(低耦合,高內(nèi)聚)。
第五點(diǎn):沒(méi)法很好的添加緩存。
畫(huà)外音:這一點(diǎn)很致命。
大部分互聯(lián)網(wǎng)業(yè)務(wù)是讀多寫(xiě)少的業(yè)務(wù),數(shù)據(jù)庫(kù)讀取最容易成為瓶頸,常見(jiàn)提升讀性能的方式是,增加緩存。
如上圖,讀服務(wù)的下游增加一個(gè)緩存,當(dāng)有讀請(qǐng)求訪問(wèn)時(shí):
(1)先訪問(wèn)緩存,如果命中,直接返回;
(2)如果緩存不命中,訪問(wèn)數(shù)據(jù)庫(kù),然后將數(shù)據(jù)放入緩存中,以便下一次能夠命中;
額,然后,這個(gè)架構(gòu)中,這個(gè)方案是不可行的。因?yàn)椋瑢?xiě)服務(wù)修改數(shù)據(jù)庫(kù)時(shí),緩存中的數(shù)據(jù)沒(méi)有辦法得到淘汰!!!
OK,有朋友說(shuō),寫(xiě)數(shù)據(jù)庫(kù)之前,可以由寫(xiě)服務(wù)來(lái)淘汰緩存:
即,讀服務(wù)與寫(xiě)服務(wù)都可以操作緩存。額,這個(gè)設(shè)計(jì),又違背了“服務(wù)化緩存私有”的微服務(wù)初衷,兩個(gè)服務(wù)因?yàn)橥环菥彺尜Y源訪問(wèn)而耦合在一起,當(dāng)緩存資源發(fā)生變化的時(shí)候,有兩個(gè)依賴點(diǎn)需要修改。
畫(huà)外音:緩存訪問(wèn),應(yīng)該收口。
況且,如果真的兩個(gè)服務(wù)訪問(wèn)相同的數(shù)據(jù)庫(kù)和緩存,為什么不合成一個(gè)服務(wù)呢?
硬要拆成兩個(gè)服務(wù),不是自己玩自己么?
OK,有另外的朋友說(shuō),可以由寫(xiě)服務(wù)發(fā)消息來(lái)淘汰緩存:
如上圖:
(1)緩存私有,只有讀服務(wù)操縱緩存;
(2)數(shù)據(jù)庫(kù)發(fā)生寫(xiě)請(qǐng)求時(shí),寫(xiě)服務(wù)給MQ發(fā)消息,由讀服務(wù)來(lái)淘汰緩存;
這種設(shè)計(jì):
(1)讀服務(wù)來(lái)淘汰緩存,本質(zhì)是一個(gè)寫(xiě)請(qǐng)求,不是很奇怪么?
(2)引入了一個(gè)MQ組件,引入更大的一致性風(fēng)險(xiǎn);
(3)讀服務(wù)和寫(xiě)服務(wù)如果是一個(gè)進(jìn)程,豈不是更好么,干嘛硬要跨進(jìn)程通信呢?
所以,還是一個(gè)服務(wù)更好:
(1)調(diào)用方不蒙圈,不糾結(jié);
(2)好維護(hù);
(3)數(shù)據(jù)庫(kù),緩存私有,無(wú)耦合;
總的來(lái)說(shuō),個(gè)人的意見(jiàn)是:
互聯(lián)網(wǎng)微服務(wù)架構(gòu),建議按照“子業(yè)務(wù)”進(jìn)行微服務(wù)拆分,而不應(yīng)該按照“讀寫(xiě)”來(lái)進(jìn)行微服務(wù)拆分,避免過(guò)度設(shè)計(jì)。
以上僅為個(gè)人架構(gòu)經(jīng)驗(yàn),希望邏輯是清晰的,供大伙參考,歡迎共同探討。
【本文為51CTO專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】






































