什么?你的团队没有100人,那就不要用微服务了!
作者 | Justin Etheredge
譯者 | 平川
編輯 | 萬佳、Tina
行業(yè)新趨勢?這些公司微服務(wù)沒用上 3 年就放棄了!
微服務(wù)正在統(tǒng)治世界,甚至有可能正在成為新的默認(rèn)選項。
O'Reilly 調(diào)查了 1283 個企業(yè),有 52%的受訪者表示他們正在使用微服務(wù)進(jìn)行軟件開發(fā)。其中超過 28%使用微服務(wù)超過三年,超過 55%使用微服務(wù)的時間為一到三年。O'Reilly 還指出企業(yè)對微服務(wù)的興趣可能達(dá)到或接近頂峰。
這幾年,有無數(shù)的中小團(tuán)隊在微服務(wù)上陷入了掙扎。微服務(wù)有好處但也存在弊端和風(fēng)險,業(yè)務(wù)不斷發(fā)展,微服務(wù)也更加復(fù)雜,一些企業(yè)權(quán)衡利弊后甚至選擇了退回單體架構(gòu)。今年有好幾個公司總結(jié)了他們放棄微服務(wù)實(shí)踐的事情。
Uber 支付體驗(yàn)平臺放棄了微服務(wù),轉(zhuǎn)而使用了合理規(guī)模服務(wù)。
4 月 6 日,Uber 支付體驗(yàn)平臺的工程經(jīng)理 Gergely Orosz 發(fā)布推文表示其團(tuán)隊的架構(gòu)方向已經(jīng)發(fā)生了變化,放棄微服務(wù),轉(zhuǎn)而使用宏服務(wù)。
為什么會做出這樣的選擇呢?Gergely Orosz 表示:“最早,Uber 通過構(gòu)建微服務(wù)來完成很小的需求或功能,以至于出現(xiàn)了很多由一個人構(gòu)建維護(hù)的微服務(wù)。這些微服務(wù)的存在給我們帶來了新的復(fù)雜性和挑戰(zhàn),例如監(jiān)控、測試、持續(xù)集成 / 持續(xù)交付(CI/CD)、服務(wù)級別協(xié)議(SLA)、跨所有微服務(wù)的庫版本(安全和時區(qū)問題)等等。”
因此,在創(chuàng)建新平臺的時候,Uber 支付體驗(yàn)團(tuán)隊對新服務(wù)進(jìn)行了更加深思熟慮的規(guī)劃:不再只是完成一件事,而是使其服務(wù)于一項業(yè)務(wù)功能,由 5-10 個工程師負(fù)責(zé)維護(hù)。Gergely Orosz 把這樣的服務(wù)規(guī)劃稱之為宏服務(wù)。
要在正確的時間選擇正確的解決方案來構(gòu)建產(chǎn)品。
Botify 是一家從事 SEO 優(yōu)化的公司,其平臺于 2012 年在 Python/Django 技術(shù)棧上創(chuàng)建。2016 年初,整個 Botify 平臺都是通過 Django 應(yīng)用程序的負(fù)載均衡集群提供服務(wù)。
2016 年年底,Botify 工程團(tuán)隊想讓工程師和產(chǎn)品經(jīng)理擁有更多的局部所有權(quán),從而可以快速輕松地將他們的產(chǎn)品和技術(shù)棧投入使用。為此,他們決定將他們的 Django 應(yīng)用程序拆分為微服務(wù)。當(dāng)時,他們的團(tuán)隊大約為 15 人。他們從身份驗(yàn)證和授權(quán)入手實(shí)現(xiàn)第一個微服務(wù),將 Django 應(yīng)用程序當(dāng)前的一部分功能轉(zhuǎn)移到微服務(wù)中。微服務(wù)模塊也需要和其他的 Django/Python 單體模塊進(jìn)行通訊。
Botify 的平臺是一個企業(yè)級 B2B 服務(wù),幫助網(wǎng)絡(luò)上最大的網(wǎng)站改善他們的 SEO,主要挑戰(zhàn)在于對客戶數(shù)據(jù)的分析。處理用戶相關(guān)數(shù)據(jù)的微服務(wù)架構(gòu)旨在服務(wù)于高流量的 B2C 平臺,而 Botify 的挑戰(zhàn)在于動態(tài)地聚合數(shù)以 GB 的 SEO 數(shù)據(jù),使其在幾秒鐘內(nèi)可用。對大約一萬名客戶的元數(shù)據(jù)以毫秒為單位進(jìn)行響應(yīng),這項任務(wù)不需要高度可伸縮的微服務(wù)架構(gòu)。恰恰相反,Botify 的后端到后端通信減慢了這些簡單的檢索過程,花費(fèi)了更多的時間。
鑒于每天都要在 JavaScript 身份驗(yàn)證后端和 Django 模塊之間頻繁地來回切換,權(quán)衡架構(gòu)的優(yōu)缺點(diǎn)以及潛在的遷移成本后,他們做出了大膽的選擇,將身份驗(yàn)證后端重新加入到 Django 單體中。
Botify 于今年 2 月停用了微服務(wù)。其團(tuán)隊負(fù)責(zé)人 David Wobrock 表示:“每一種技術(shù)都自有其用途,但我們相信,要在正確的時間選擇正確的解決方案來構(gòu)建我們的產(chǎn)品。如今,我們不必來回切換了,也不用維護(hù)兩個后端了,顯然,我們已經(jīng)從中獲益。“
“我們公司也從單體轉(zhuǎn)向了微服務(wù),但最后在二者之間找到了一個平衡點(diǎn)。”
在 2017 年的時候,辦公管理軟件公司 Managed by Q 的技術(shù)團(tuán)隊大概有 20 名工程師,應(yīng)用程序是一個部署在 ECS 上的 Django 單體。為了趕上現(xiàn)代化開發(fā)實(shí)踐的步伐,他們開始轉(zhuǎn)向了微服務(wù)架構(gòu)。
但隨著微服務(wù)數(shù)量的增長,事情不像之前那么順利了。
每多一個新服務(wù),就會增加一些基礎(chǔ)設(shè)施。比如,一個 ECS 服務(wù)、一個 Postgres 實(shí)例或一個 RabbitMQ 實(shí)例。CI/CD 的配置也會增加,還需要進(jìn)行第三方服務(wù)(比如 Rollbar/Sentry)配置。依賴也需要更新,而且需要更新依賴的地方越來越多。基礎(chǔ)設(shè)施團(tuán)隊在項目上花了很多時間,為每一個服務(wù)重復(fù)著枯燥無味的工作。而且小型的服務(wù)容易被人忽略,在運(yùn)行起來之后,基本上會被擱在一邊,最后就會過時。
如果服務(wù)邊界沒有搞清楚,還會顯著降低功能的開發(fā)速度,這是微服務(wù)的一個很大的風(fēng)險點(diǎn)。開發(fā)一個跨多個服務(wù)的功能需要做更多的工作,而重構(gòu)一個跨多個服務(wù)的功能是一個噩夢。如果服務(wù)邊界很清晰,大部分項目只會影響到一個服務(wù)。但是,對于初創(chuàng)公司來說,它們的發(fā)展方向是不可預(yù)測的。一個產(chǎn)品的兩個部分在一開始可能是完全獨(dú)立的,但一年之后可能會變得緊密耦合起來。所以,要完全清晰地定義服務(wù)邊界不是件容易的事。
最后,在轉(zhuǎn)向微服務(wù)兩年之后,他們開始合并微服務(wù)。一些微服務(wù)被合到了單體中,其他的則合并成較大的服務(wù)。在一年中總共移除了 9 個微服務(wù)。大小合理的服務(wù)承擔(dān)著相當(dāng)大的責(zé)任,大多數(shù)功能開發(fā)都可以在單個服務(wù)中完成。
不能當(dāng)然地認(rèn)為微服務(wù)就是正確的選擇。
微服務(wù)已經(jīng)被這代人當(dāng)成銀彈,不過,上面提到的這些企業(yè)已開始用更挑剔的眼光來看待它。這些例子中,他們認(rèn)為轉(zhuǎn)向微服務(wù)的工程開銷太大,不值得。而這樣的案例還有很多。
每個系統(tǒng)實(shí)現(xiàn)都會有一些錯誤的選擇。但是,他們所犯的最大的錯誤與他們的微服務(wù)實(shí)現(xiàn)無關(guān)。他們所犯的最大錯誤是在只有 20 名工程師的環(huán)境中實(shí)現(xiàn)了幾十個微服務(wù)。
如果你認(rèn)為,“在一個只有 20 名工程師的團(tuán)隊中實(shí)現(xiàn)大量的微服務(wù)簡直是瘋了!”那么,我同意你的看法。但這種情況隨處可見,這至少表明沒有一種單一的架構(gòu)模式適合所有的人。
我從三年前就開始寫這篇博文了,期間,我無數(shù)次聽說有中小型團(tuán)隊在微服務(wù)上陷入了掙扎,現(xiàn)在,我終于準(zhǔn)備好發(fā)表了。我寫這篇文章不是因?yàn)槲矣憛捨⒎?wù),而是因?yàn)槲覔?dān)心微服務(wù)正在成為新的默認(rèn)選項。“你不用微服務(wù)嗎?那么顯然,你沒把軟件工程當(dāng)回事。”人們不再做決定,他們只是想當(dāng)然地認(rèn)為微服務(wù)就是正確的選擇,我認(rèn)為這是有問題的。
規(guī)模決定一切
你的系統(tǒng)有多少人在開發(fā)?五個?十個?五十?一百?還是一千?如果你的應(yīng)用程序、平臺、應(yīng)用程序套件或其他任何東西,有超過 500 人在開發(fā),那么我認(rèn)為,你大可以放心地關(guān)掉這篇博文并繼續(xù)前進(jìn)。你們的問題不是我們這里要討論的問題。但是,如果你的應(yīng)用程序開發(fā)工程師不足 100 人,那么請別走,我們聊一會兒。如果你的情況介于兩者之間,那么這就要看實(shí)際情況了,也請不要走開,看看是否能發(fā)現(xiàn)一些有用的東西。
我職業(yè)生涯的大部分時間都服務(wù)于做小東西的公司。我在大公司做過不少咨詢工作,但我工作過的大多數(shù)公司(或者是部門)都總共只有不到 100 名軟件工程師。通常,這類工程組織有一個共同的關(guān)注點(diǎn):創(chuàng)建可靠且穩(wěn)定的系統(tǒng),為業(yè)務(wù)交付價值——所有這些都需要借助緊張的工程資源。
我所處理的問題都不是在谷歌、Facebook 或 Uber 那種規(guī)模上。在有些人看來,我似乎不知道自己在做什么,但就我個人而言,我認(rèn)為這是一種資產(chǎn)。我認(rèn)識的在這類機(jī)構(gòu)中工作的人都很聰明,但他們不是魔法師。
在一個大型工程環(huán)境中工作,意味著用幾乎無法估量的工程資源大規(guī)模地解決問題。通常,他們有大量的內(nèi)部工具和庫可以使用,這使他們能夠編寫大規(guī)模的軟件。與來自大型工程環(huán)境背景的人交流得越多,我就越意識到,對于我們這些人來說,在一家初創(chuàng)企業(yè)或中小型企業(yè)中,與由 5 名、10 名甚至 50 名工程師組成的團(tuán)隊打交道是多么困難。
建議是要看上下文的
在如此大的規(guī)模下,溝通和協(xié)調(diào)是迄今為止最大的挑戰(zhàn)之一,這是有道理的。減少團(tuán)隊之間的依賴關(guān)系,或者讓應(yīng)用程序擴(kuò)展到每秒處理數(shù)百萬個請求,規(guī)模這么大,這樣的需求完全值得付出如此巨大的工程開銷。
但是,對于中小型企業(yè),我經(jīng)常聽到這樣的建議:
-
你需要重新構(gòu)建一個更現(xiàn)代化的軟件棧;
-
你應(yīng)該使用擴(kuò)展性更好的數(shù)據(jù)存儲;
-
你的數(shù)據(jù)工程團(tuán)隊可以切換到 Kafka 嗎?
-
你應(yīng)該重構(gòu)成一系列的微服務(wù);
-
你需要用 Go、Rust 或其他高可擴(kuò)展的語言進(jìn)行重寫。
通常,這些中小型團(tuán)隊發(fā)現(xiàn),僅僅是滿足特性請求和提供支持就很困難,更不用說考慮重寫整個應(yīng)用程序了。這個建議合適嗎?當(dāng)然,在很少一些情況下可能是合適的。但是,有小企業(yè)和創(chuàng)業(yè)公司一再告訴我,他們從導(dǎo)師或顧問那里聽說過這些。
是不是有的建議聽著很熟悉?
當(dāng)你需要應(yīng)對一個小型團(tuán)隊和一個大型應(yīng)用程序時,這可能會讓人膽怯。你會感覺到各種壓力,協(xié)調(diào)特性發(fā)布,隨著系統(tǒng)復(fù)雜性的增長開發(fā)速度下降,你開始閱讀很多文章,了解如何將應(yīng)用程序分解成很多小塊,從而幫助你降低復(fù)雜性,提高部署頻率,簡化開發(fā)工作。
所以,你決定從只有 20 人的工程師團(tuán)隊里抽出一大部分人,和少量的工程承包人員一起,在接下來的兩年里重新規(guī)劃設(shè)計你的應(yīng)用程序,拆分你的系統(tǒng),并構(gòu)建出幾十個微服務(wù),可能還有一些微前端。在新構(gòu)建的應(yīng)用程序上線后,你很快就會發(fā)現(xiàn),部署確實(shí)越來越頻繁。每個微服務(wù)的代碼庫都很小,推斷也比較容易。小型的更新和 Bug 修復(fù)可以更快地完成、測試和上線。你對自己說:“太棒了!這肯定會提高開發(fā)團(tuán)隊的開發(fā)速度!”
?新挑戰(zhàn)
但是,接下來的幾個月里,你開始遇到一些挑戰(zhàn)。
?協(xié)調(diào)
每當(dāng)需要進(jìn)行較大的更改時,你就會發(fā)現(xiàn)自己需要更新許多服務(wù),并且要協(xié)調(diào)這些服務(wù)的發(fā)布。當(dāng)你向同事提起這件事時,他們總是說:“你弄錯了。你的服務(wù)在邏輯上應(yīng)該是分離的。”邏輯上分離,聽起來很好,但是,你已經(jīng)將系統(tǒng)拆分成許多小塊,所以這些小塊之間有很多依賴關(guān)系。有人曾經(jīng)說過,如果你的服務(wù)之間有一堆依賴關(guān)系,那么你的拆分邊界就有問題,但是,除了大幅減少微服務(wù)的數(shù)量外,你并不知道其他的拆分方法。
?數(shù)據(jù)一致性
你還會注意到,出現(xiàn)了一些數(shù)據(jù)一致性的新問題。看起來,應(yīng)用程序中一些過去在單個操作中完成的操作現(xiàn)在被拆分到幾個不同的服務(wù)中,其中一個服務(wù)有一些寫入失敗。同樣,你的同事會告訴你,這樣做是不對的,但是,將庫存服務(wù)與訂單服務(wù)拆分成單獨(dú)的服務(wù)似乎是正確的,是符合微服務(wù)的精神的。你告訴自己,“也許,我們需要著手設(shè)計跨所有這些操作的多階段提交,或者我們需要構(gòu)建工具來確保數(shù)據(jù)一致性。”再一次,這讓你覺得會明顯增加一些工程復(fù)雜性和開銷。
?性能挑戰(zhàn)
性能問題也開始悄然出現(xiàn)——應(yīng)用程序中的一些頁面需要調(diào)用六個服務(wù)來呈現(xiàn),加載時間很長。看起來,你需要為其中一些服務(wù)實(shí)現(xiàn)一個內(nèi)部緩存層,以加快頁面呈現(xiàn)速度。簡單的緩存層不會特別麻煩,只是需要再添加一層。
?分布式跟蹤
隨著時間的推移,你還會開始注意到,團(tuán)隊記錄的處理某些 Bug 的時間顯著增加。當(dāng)你與團(tuán)隊討論這個問題時,他們會說,某些問題在系統(tǒng)中很難定位。即使他們找到了,也很難再現(xiàn)它們,因?yàn)樵诠こ處煹臋C(jī)器上讓多個服務(wù)進(jìn)入同樣的狀態(tài)會是一項巨大的挑戰(zhàn)。你默默地記了下來,你需要從整體上做個規(guī)劃,以便提供更好的系統(tǒng)級可跟蹤性,這樣,你就可以看到請求在整個系統(tǒng)中的流轉(zhuǎn)過程。又多了一個待辦事項。
?重復(fù)
現(xiàn)在,設(shè)計和構(gòu)建某些比較大的特性需要花費(fèi)更長的時間了。它們需要多個不同的服務(wù)來實(shí)現(xiàn)不同的功能,并在不同的數(shù)據(jù)存儲中協(xié)調(diào)更改。你會發(fā)現(xiàn),自己在不同的服務(wù)中復(fù)制了某些業(yè)務(wù)操作的邏輯,盡管你已經(jīng)盡了最大的努力來保證每個服務(wù)在邏輯上是獨(dú)立的,但是,你沒法完全做到這一點(diǎn)。這給表帶來了各種不同的風(fēng)險,因?yàn)楝F(xiàn)在需要在服務(wù)之間保持業(yè)務(wù)邏輯的一致性。這是否意味著創(chuàng)建共享服務(wù)?手動保持邏輯同步?一聲嘆息。
?安全面
另一個關(guān)鍵點(diǎn) CVE 呢?謝天謝地,你花時間在構(gòu)建過程中引入了工具,使你能夠知道哪個服務(wù)受了影響,因?yàn)闉樗羞@些服務(wù)打補(bǔ)丁是非常困難的。手工審計每一個服務(wù)將是一項艱巨的任務(wù)。盡管如此,因?yàn)橐粋€ CVE 版本而部署 24 個服務(wù)是一種你沒有真正考慮到的痛苦。
?報表挑戰(zhàn)
如果將數(shù)據(jù)拆分到多個數(shù)據(jù)存儲,一些查詢就會變得非常復(fù)雜。因此,你聘請了一些顧問來幫助你構(gòu)建一個專用的數(shù)據(jù)倉庫并創(chuàng)建一個 ETL 過程,將其轉(zhuǎn)換為讓你的團(tuán)隊可以輕松生成報告的形式。這種設(shè)置提供了一些預(yù)期的優(yōu)點(diǎn),但是,現(xiàn)在每次進(jìn)行重要的模式更改都必須同時維護(hù) ETL 過程。又多了一件事要處理。
?穩(wěn)定性
最后,穩(wěn)定性開始出現(xiàn)問題。其中一個服務(wù)有點(diǎn)不穩(wěn)定,在訪問它時會導(dǎo)致系統(tǒng)的其他部分掛起。現(xiàn)在,你看到的不是拋出的錯誤,而是請求靜靜地阻塞在那里,直到失去響應(yīng)。你知道,你的團(tuán)隊沒有花足夠的時間來確保服務(wù)之間良好的容錯能力,因此你意識到,可能需要使某些交互異步進(jìn)行,這將進(jìn)一步增加工程開銷。
這非常令人沮喪,因?yàn)槟愕膱F(tuán)隊做了大量的研究,并試圖遵循所有可接受的模式來實(shí)現(xiàn)良好的微服務(wù),但這種轉(zhuǎn)變帶來的開銷似乎并不值得。是的,單個服務(wù)的開發(fā)和部署更容易,但是,系統(tǒng)整體的復(fù)雜性高了許多。其中一些痛點(diǎn)可以通過額外的工程和一些更好的模式來緩解,但是,這就違背你最初的目標(biāo)了——你應(yīng)該提高速度,用更少的資源做更多的事情,而不是增加系統(tǒng)的工程開銷。也許你在尋找靈丹妙藥,并做出了一些輕率的決定。
考慮下你面臨什么問題?
也許你已經(jīng)經(jīng)歷過一些這樣的痛苦,并且深有感觸,或者你轉(zhuǎn)到了微服務(wù),這對你的團(tuán)隊來說是一個巨大的進(jìn)步。在很多情況下,都有必要拆分出一些服務(wù),但這完全取決于你面臨的問題。
你的痛苦是為了有效地協(xié)調(diào)多個團(tuán)隊對同一個單體應(yīng)用程序所做的更改嗎?你的痛苦是否無法通過其他策略(如基于主干的開發(fā))來解決?你可能需要將其拆分,創(chuàng)建一些服務(wù),并考慮微服務(wù)的意義所在。
你是否感到非常痛苦,因?yàn)槟隳莻€有著數(shù)百萬行代碼的龐大單體需要做出一些犧牲并需要幾天的時間來部署?你需要把它拆分并開發(fā)成服務(wù)。
在你的應(yīng)用程序中,是否有大量不相關(guān)的功能混雜在一個系統(tǒng)中?你可能需要一些服務(wù),或者更小的應(yīng)用程序。
你那擁有 30 名工程師的團(tuán)隊是否深陷復(fù)雜性,開發(fā)速度很低,而大家都把原因歸咎于單體應(yīng)用程序?你可能需要首先關(guān)注一個更好的單體,然后再考慮遷移到一些服務(wù)或一組較小的應(yīng)用程序。
正如 Simon Brown 曾經(jīng)說過的那樣:“如果你不能構(gòu)建一個結(jié)構(gòu)良好的單體,你憑什么認(rèn)為微服務(wù)就是答案?”
復(fù)雜性被轉(zhuǎn)移,但并未被消除
通過采用微服務(wù)或微前端,你是在轉(zhuǎn)移復(fù)雜性,而不是消除復(fù)雜性。在一些地方,這種轉(zhuǎn)變是值得的,但是,如果你的系統(tǒng)不夠大,你的團(tuán)隊成員不夠多,而你面臨的問題不是來自于協(xié)調(diào)大量的開發(fā)人員,那么將應(yīng)用程序拆分成很多小塊可能會弊大于利。
我并不是說,小型團(tuán)隊不應(yīng)該把業(yè)務(wù)分解為大小合理的服務(wù),也不是說你不應(yīng)該將那些功能過多的應(yīng)用程序拆分。但多年來,我看到太多的人提出這樣的建議:把你的系統(tǒng)分解成很多很多的小塊,就能神奇地解決你所有的問題。
你需要清楚地了解你的系統(tǒng)所面臨的挑戰(zhàn),看看整個團(tuán)隊不斷增加的速度是否可以抵消構(gòu)建分布式系統(tǒng)所帶來的額外復(fù)雜性,然后再做出決策。如果你有證據(jù)證明這種取舍是值得的,那么根據(jù)你的業(yè)務(wù)領(lǐng)域和團(tuán)隊規(guī)模來拆分出合理的服務(wù)。務(wù)必要非常關(guān)注微服務(wù)的最佳實(shí)踐,否則你最終將構(gòu)建一個分布式的單體,這將是最糟糕的結(jié)果。
請注意,本文還沒有涉及從單體遷移到微服務(wù)的復(fù)雜性,不要低估了這種復(fù)雜性。這是一個需要非常謹(jǐn)慎的過程,并且應(yīng)該增量地完成。
嚴(yán)格考察,謹(jǐn)慎行事
我建議你嚴(yán)格地考察權(quán)衡。考慮一下,你的團(tuán)隊是否會從中受益,然后從小規(guī)模實(shí)驗(yàn)入手,拆分出一些服務(wù),看看效果如何。克服挑戰(zhàn),覺得有意義再繼續(xù)前進(jìn)。然后,重復(fù)上述過程。我知道,這可能與如今科技行業(yè)“快速行動,改變一切”的理念不符,但你最終會為自己采取了慎重的做法而高興。
參考閱讀:
https://www.simplethread.com/gasp-you-might-not-need-microservices/
總結(jié)
以上是生活随笔為你收集整理的什么?你的团队没有100人,那就不要用微服务了!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干掉 “User”
- 下一篇: 研究了 2 天,终于知道 JDK 8 默