微服務(wù)的災(zāi)難:折磨人的環(huán)境!
本文轉(zhuǎn)載自微信公眾號(hào)「腦子進(jìn)煎魚(yú)了」,作者陳煎魚(yú)。轉(zhuǎn)載本文請(qǐng)聯(lián)系腦子進(jìn)煎魚(yú)了公眾號(hào)。
大家好,我是煎魚(yú)。
我有一個(gè)好朋友小咸魚(yú),他們經(jīng)過(guò)服務(wù)化拆分《微服務(wù)的災(zāi)難:拆的很爽,但服務(wù)太小》的磕磕碰碰后,由于一個(gè)人負(fù)責(zé) N 倍數(shù)的服務(wù),多開(kāi) IDE,深夜加班,一個(gè)不小心,犯迷糊了,就誤操作,邏輯寫錯(cuò)服務(wù)了,就出事故了。
隨后,在小咸魚(yú)的 Leader 帶領(lǐng)下,經(jīng)過(guò)會(huì)議室多輪爭(zhēng)吵后??偹闶侵匦抡?、設(shè)計(jì)了一版服務(wù)邊界,分分合合,原本拆了的合回去,又增添了新服務(wù)組合。
于是,小咸魚(yú)又可以愉快的 hello world 起來(lái)了。這難道就是事故驅(qū)動(dòng)開(kāi)發(fā)的威力!
但,沒(méi)開(kāi)心兩天。又遇到了新的問(wèn)題...
服務(wù)依賴
一般來(lái)講,在拆分為微服務(wù)后。經(jīng)歷一段時(shí)間的業(yè)務(wù)規(guī)模發(fā)展后,我們的服務(wù)都是具有比較多的依賴。像是:
一個(gè)服務(wù)依賴其他多個(gè)服務(wù)
我們發(fā)現(xiàn)業(yè)務(wù)初始依賴的是 ServiceA,結(jié)果跑了一段時(shí)間后。服務(wù)依賴越來(lái)越多,還出現(xiàn)了更進(jìn)一步依賴,Service A 依賴 B、C,他們背后又調(diào)用了一大堆的服務(wù)。
同時(shí) ServiceA 依賴的服務(wù),還存在跨業(yè)務(wù)組的情況,也就是一個(gè)普通的業(yè)務(wù)調(diào)用,可能關(guān)系到多個(gè)業(yè)務(wù)組的協(xié)調(diào):
一次調(diào)用涉及 3 個(gè)業(yè)務(wù)組
雖然從圖示來(lái)看,只有 3 個(gè)業(yè)務(wù)組。但,一個(gè)月前可是都是依賴自己。
說(shuō)明小咸魚(yú)作為業(yè)務(wù)組 A 的維護(hù)方,他所依賴的業(yè)務(wù)團(tuán)隊(duì)正在不斷地增大,大家都在用力產(chǎn)生新的服務(wù)依賴。
假以時(shí)日,這個(gè)服務(wù)的依賴必然變的非常多(不過(guò),小咸魚(yú)并沒(méi)有意識(shí)到這一點(diǎn))。
開(kāi)發(fā)環(huán)境
終于,在小咸魚(yú)維護(hù)了一段時(shí)間后。這一個(gè)業(yè)務(wù)產(chǎn)品,成功走過(guò)了嘗試期。他有了好幾位新同事,在迭代的過(guò)程中,聯(lián)調(diào)的訴求出現(xiàn)了。
小咸魚(yú)麻利的利用組織里的公共開(kāi)發(fā)環(huán)境搭建起了服務(wù):
公共開(kāi)發(fā)環(huán)境
小咸魚(yú)辛辛苦苦的找了其他幾個(gè)組,讓大家都往上面 Push 自己的服務(wù),解決了這一個(gè)迭代的聯(lián)調(diào)的問(wèn)題。
但,好景不長(zhǎng)。業(yè)務(wù)壓力總是大的,大家都維護(hù)著復(fù)數(shù)的 f 分支。這時(shí)候就遇到了新問(wèn)題:
不同業(yè)務(wù)組期望依賴不同
業(yè)務(wù)組A,期望依賴的是:
- ServiceA:v0.1.0。
- ServiceB:v0.2.0。
- ServiceC:v0.3.0。
業(yè)務(wù)組B,期望依賴的是:
- ServiceA:v1.1.0。
- ServiceB:v1.2.0。
- ServiceC:v1.3.0。
好家伙,在同一個(gè)集成開(kāi)發(fā)環(huán)境中,大家期望依賴的服務(wù)版本壓根不一樣。聯(lián)調(diào)起來(lái)挺費(fèi)勁,甚至存在一些風(fēng)險(xiǎn)。
例如:你在開(kāi)發(fā)環(huán)境,聯(lián)調(diào)時(shí)你以為你依賴的 ServiceB 的 v0.2.0 版本,跑的也好好的。結(jié)果其實(shí)其他業(yè)務(wù)在晚上把他更新為 v0.5.0 版本了,接口還是兼容的,但內(nèi)在邏輯是變了的。當(dāng)然,你也沒(méi)有發(fā)現(xiàn)這個(gè)問(wèn)題,因?yàn)槭?“細(xì)微” 的修改。
但上到測(cè)試環(huán)境后,很快就會(huì)出現(xiàn)被測(cè)試同學(xué)打回來(lái)的情況。以此往來(lái)多了,你就會(huì)成為團(tuán)隊(duì)里質(zhì)量不好的那一位 TOP1 了...
這問(wèn)題怎么解決呢?
解決方案
針對(duì)微服務(wù)架構(gòu)下的開(kāi)發(fā)環(huán)境,核心還是要看公司內(nèi)的基礎(chǔ)設(shè)施建設(shè)的怎么樣。
公共 dev 分支
若只是基礎(chǔ)底蘊(yùn)不夠深厚,鈔能力也不夠的,一般會(huì)采取 dev 分支合并的方式。也就是在 ServiceA 上建立 dev 分支,專門用于集成開(kāi)發(fā)環(huán)境。由開(kāi)發(fā)同學(xué)配合腳本等,進(jìn)行維護(hù)和應(yīng)用。
雖然容易出現(xiàn)不同分支,影響到同一塊的內(nèi)容。但由于同一個(gè) Service 一般會(huì)由 1~3 個(gè)人(小團(tuán)隊(duì))經(jīng)手維護(hù),都坐在附近,基本可以控制沖突。
甚至有的小伙伴,為了謹(jǐn)慎起見(jiàn)。合并前會(huì)反向合并到自己 f 分支,再跑一遍自己的自動(dòng)化接口測(cè)試,以確保正確。
當(dāng)然,測(cè)試環(huán)境也是一樣的問(wèn)題。在業(yè)務(wù)迭代的過(guò)程中,常常有多個(gè)功能在同時(shí)開(kāi)發(fā),會(huì)拉多個(gè)分支。
- 如果開(kāi)發(fā)、測(cè)試環(huán)境只有一套,就意味著要么團(tuán)隊(duì)內(nèi)部商量好時(shí)間。
- 輪流使用測(cè)試環(huán)境,要把不同功能的分支代碼合到某個(gè)分支再統(tǒng)一解沖突,再聯(lián)調(diào)和測(cè)試。
這個(gè)方案只能治標(biāo),但不能完全治本。
多泳道環(huán)境
說(shuō)白了,可能還是需要多套環(huán)境來(lái)解決。當(dāng)你期望是某一個(gè)泳道用來(lái)發(fā)布某一個(gè)特性分支時(shí)。對(duì)應(yīng)的發(fā)布系統(tǒng)就會(huì)給其相關(guān)聯(lián)的組件打上泳道標(biāo)識(shí),自然也就能知道依賴的是誰(shuí)了。
如下圖:
一個(gè)服務(wù)存在多個(gè)泳道
一般客戶端會(huì)帶上泳道標(biāo)識(shí)的 Header,再一路透?jìng)飨氯?。所有相關(guān) Proxy 會(huì)根據(jù) Header 內(nèi)的標(biāo)識(shí)進(jìn)行選擇。
考慮到有的服務(wù)在功能特性中并沒(méi)有變更,因此會(huì)有 master 和功能泳道的區(qū)別,會(huì)再根據(jù) Proxy 的規(guī)則進(jìn)行選擇。
當(dāng)然在這塊也可以結(jié)合服務(wù)發(fā)現(xiàn)的機(jī)制去做,具體看技術(shù)選型上的差距了。
總結(jié)
微服務(wù)化后,N 個(gè)服務(wù)如何聯(lián)調(diào),就是開(kāi)發(fā)人員的一個(gè)大頭疼問(wèn)題。而人一多,業(yè)務(wù)壓力一大,很可能會(huì)出現(xiàn)一個(gè)服務(wù)同時(shí)多個(gè)分支并行開(kāi)發(fā)的情況。
也就會(huì)導(dǎo)致開(kāi)發(fā)、測(cè)試環(huán)境同一時(shí)間遇到這個(gè)煩人問(wèn)題,我們可以通過(guò)公共分支,又或是多泳道的方式解決。
但兩者都存在不同程度的缺點(diǎn):
公共環(huán)境,需要公共分支,需要人為的一定介入。
多泳道環(huán)境,需要的基礎(chǔ)設(shè)施建設(shè)較多,同時(shí) MySQL、Redis 等公共介質(zhì)也是一個(gè)問(wèn)題,成本也是運(yùn)維的一個(gè)考慮因素。
沒(méi)有任何一個(gè)方案是絕對(duì)的銀彈。