为什么Segment会从微服务退回单体架构?
近年來,我們發布了很多文章介紹企業向微服務遷移的成敗經驗。最近,Segment的Alexandra Noonan寫了一篇文章,講述了他們從單體架構遷移到微服務,之后又退回單體應用的經歷。文中Alexandra具體介紹了他們從原來的簡單架構遷移到微服務的過程:
\\\我們原來有個API負責攔截事件并將它們轉發到一個分布式的消息隊列中。這里的一個事件指的是由網頁或移動應用生成的,包含用戶與用戶動作信息的JSON對象。當隊列中的事件被消費后,系統會檢查用戶設置來決定接收事件的目標。(……)之后事件被逐個發送到每個目標的API。這樣的流程很合理,因為開發者只需要將事件發送到Segment的API這一個目標即可,無需創建幾十個集成。
\\\如果事件交付失敗,就會被系統重新加入隊列,也就是說有時工作者進程要一邊發送新的事件,一邊嘗試重新發送之前失敗的事件。這樣會導致所有目標都出現延遲,Alexandra解釋說:
\\\為解決最緊迫的阻塞問題,團隊為每個目標各創建了一個獨立的服務和隊列。這一新架構包括一個新的路由進程,它會接收入站事件并向每個選定的目標分發一份該事件的拷貝。現在如果某個目標出現問題,只有它自己的隊列會回溯,不會影響其它目標。這一微服務化的架構將各個目標獨立開來,這樣當某個目標又出現常遇到的問題時就會非常有用。
\\\文章之后寫到,Segment的開發團隊一開始將所有代碼存放在一起,但這引發了許多問題:
\\\最大的麻煩在于,只要一個測試崩潰,那么所有目標的測試都會失敗。當我們試圖部署一項改動時,我們必須先費勁修復崩潰的測試,就算改動與一開始的變動毫無關聯也得這樣做。為了解決這個問題,我們決定將代碼拆分到每個目標各自的存儲庫里。
\\\這樣一來開發團隊的靈活性的確改善了許多。然而隨著目標數量的增加,存儲庫的數量也在同步增長。為了讓開發者免受維護這么多代碼庫的麻煩,Segment團隊創建了許多共享庫,存放所有目標通用的變換和功能。這組共享庫大大減輕了他們維護工作的壓力。但這個措施也有不太容易發現的負面影響:向共享庫更新并測試改動會花費大量時間,還會增加破壞無關目標的風險。最后這些庫開始分裂為不同的版本,各自不統一,引發了之前沒有想到的一個問題:每個目標的代碼庫都會依賴不同版本的共享庫。Alexandra承認,他們當時可以開發工具來自動將改動更新到這些庫中,但那時他們又遇到了這個微服務架構產生的一些新問題。
\\\新出現的問題是,每個服務都有自己的負載模式。有些服務一天處理幾個事件,有的服務每秒就能處理幾千個。如果目標只處理很少的事件,工作者線程就得在出現負載問題時手動擴展服務以滿足需求。
\\\他們的系統集成了自動擴展能力,但因為每個服務都需要指定CPU和內存資源分配,調整自動擴展的設置“更像玄學而非科學”。如前所述,每次存儲庫的數量增長時他們都要增加目標,最后團隊平均每月要增加三個目標,當然還要加上更多的隊列和服務。
\\\2017年初,Segment的一個產品的核心部分使我們達到了峰值負載。當時的情況下我們好像在從微服務的大樹上摔下來,一路撞上了所有的樹枝。我們這個小團隊非但沒有提升效率,反而陷入了愈加復雜的泥潭。這個架構的核心優勢都成了負擔。我們的速度暴降,故障率卻在暴增。(……)于是,我們決定回退一步,重新考慮整個流程。
\\\文章最后Noonan回顧了他們如何擺脫這個微服務架構,其中他們還開發了Centrifuge來替換所有獨立的隊列,將所有事件都發送到一個單體服務上。他們還將所有目標的代碼都遷移到一個存儲庫里,不過這一次新增了一些代碼管理的規則:所有目標都要使用同一個版本,每次更新時同步更替到新版本。他們再也不用操心各個獨立版本之間的差異了,因為所有的目標都在使用一個版本,以后也是如此。對于開發者來說,管理越來越多的目標所花費的時間減少了,風險也降低了。
\\Noonan的文章還寫了很多內容,都是關于他們退回單體服務的經歷。感興趣的讀者應該去仔細讀一下,文章里面有很多架構細節、關于存儲庫架構的思考和建立彈性測試集的方法。最后,團隊將回退的好處總結如下:
\\\2016年時我們還在使用微服務架構,我們為共享庫帶來了32項改進。而僅僅今年到現在我們就做出了46項改進。過去半年來我們為庫帶來的改進比2016年全年都多。因為所有的目標都處于同一服務內,我們可以很好地搭配CPU密集型服務和內存密集型服務,所以擴展服務以滿足性能需求變得非常容易。更大的工作者池能負載更多內容,所以我們不再需要將處理少量負載的目標掛起到頁面了。
\\\不過這個架構回退過程也有一些負面影響,包括:隔離錯誤變得更困難(一個目標的錯誤導致目標崩潰,結果會傳染到所有目標);升級一個目標的版本可能會破壞其它一些目標,于是后者也需要升級。Noonan在文章最后寫下了誠懇的總結:
\\\在微服務和單體架構之間做選擇時,要注意它們各自都有自己需要考慮的因素。我們的架構中有些部分是微服務表現更出色,但服務端的目標遷移到微服務后的一系列麻煩是一個很好的教訓,證明這一流行趨勢在某些情況下能對生產力和性能有多大負面影響。結果對于我們來說,單體架構才是最終解決方案。
\\\其實他們關于微服務的某些看法是很眼熟的。今年早些時候我們報道說,ThoughtWorks根據觀察認為微服務尚未進入普及周期。當時的報道寫到:“主要原因之一是很多組織并沒有為微服務做好準備,他們缺少一些關于運營和自動化的基礎實踐”。此外,Jan在另一篇文章中總結了多年來微服務遷移的失敗案例。Berico科技的首席軟件工程師Richard Clayton提到了他們當時遇到的一個問題:
\\\在不同服務之間共享通用功能代碼,以消滅各個服務中的重復功能的努力卻帶來了巨大的負面影響,最終導致了大規模回退。
\\\回到原文,有很多關于這個話題的討論,比如Hacker News和Reddit上的這些;有些討論者認為與微服務無關的一些因素可能導致了這些問題。比如,有些評論指出Noonan的文章并沒有引用CI,只有CD,起碼這是一個奇怪的組合。還有評論認為不止微服務會引發這些問題,所有的分布式系統都是一個樣。關于這一點我們之前也提到過,有人使用SOA時有過類似的經驗:
\\\我曾在一個類似的代碼庫中工作過,那時他們管它叫SOA,云還沒開始流行。對服務的每次調用都會啟動一個完整的服務實例。我想我們應該強制將網絡延遲規定為架構設計的要素之一。
\\\有趣的是很多討論串談到了微服務中數據上下文的問題。這個話題我們探討過很多次,這也是微服務反對者的主要論據之一。HackerNews的一條評論舉例說:
\\\比這還糟呢。據我觀察多數微服務架構根本就沒考慮一致性(“我們才不要亂七八糟的事務!”),盲目地隨大流還樂在其中。我搞不懂為啥子人們會覺得,把軟件模塊拆分開來然后用緩慢不可靠的網絡和弱爆的手動連接REST處理串起來,就能神奇地讓架構面目一新哩?我覺得人們產生這種生產力幻覺的原因是:”我把這些都搞定啦,現在我也有一套’管它是什么即服務‘的先進玩意兒嘍!看看那酷斃的數據面板上閃爍的小綠燈吧,我們可是為了它干了好幾個月呢!“
\\\另外,為微服務定義域是多年來我們一直強調的微服務部署關鍵環節。有一篇PPT介紹了如何使用DDD解構單體應用,Reddit的一個討論串也談到了這一點:
\\\建立一個出色的微服務架構是很難的。我現在覺得關鍵在于恰當地分隔你的域,當系統進化時持續關注這一層面。微服務并不像它的名字那樣,它不必非得那么小,但是要搭配適合這個架構的元素。很多人的失敗正是因為忽視了這一點。
\\\其他人怎么看?比如說,Segment的微服務架構出現的問題能否用其它方式解決,無需退回單體應用?或者一開始的單體架構是否有辦法進化得更好,解決原來的問題,而無需切換到微服務?
\\查看英文原文:Why Segment Returned to a Monolith from Microservices? ?
\\感謝冬雨對本文的審校。
總結
以上是生活随笔為你收集整理的为什么Segment会从微服务退回单体架构?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 重定向输入输出
- 下一篇: 解决JBoss只能通过localhost