【 ECUG 演講分享】吳海黎:CODING 微服務架構演進之路

近日,CODING 平臺技術總監吳海黎參加了由 ECUG 社區舉辦的技術大會,與聽衆一同分享了 CODING 微服務架構的演進歷程。讓我們一起來欣賞精彩的演講內容吧。

我是來自 CODING 的吳海黎,今天我給大家分享的內容是微服務拆分的實踐,微服務幾乎可以說是當下的一個主流架構,希望今天的分享能給大家落地微服務帶來幫助。整個分享分爲三個部分:第一是單體架構的簡介,第二是微服務架構落地方案,第三是 DevOps 之於微服務的重要性。

一、單體架構簡介

雖然第一部分是介紹單體架構的主要痛點,但是還是應該跟大家分享一下,單體應用對於我們在業務早期,業務處理單一,團隊規模較小,單體應用的中心化處理方案是能夠降低團隊的溝通成本,降低架構的複雜度,從而提高研發效率的這麼一個架構。所以是否升級微服務架構,取決於我們所處的業務階段和組織架構。介紹完單體架構的優勢,我們一起來看看 CODING 微服務改造前的 Backend Service 是什麼樣的。

首先這個架構應該是 0.5 版本的微服務架構,可以看出這個架構有一部分服務已經是拆分成獨立的微服務了,並且服務之間的註冊和發現是依賴於 ETCD 去做服務發現與註冊的事情。服務之間的通訊方式是 GRPC,我們選 GRPC 的原因是部分的服務是架在 GO 上面的,部分的服務是放在 Java 上面,所以我們需要跨語言的通訊方式。
在這裏插入圖片描述
我們可以清楚地看到這個架構存在的主要問題是服務拆分了,但是並沒有治理,服務的耦合性依然非常嚴重,比如說我們現在整個入口依然是 CODING 的主站,然後通過主站的流量分發走 GRPC 接口去調用新的服務,沒有完全的做微服務的拆分事情。服務之間的耦合性依然非常嚴重。
在這裏插入圖片描述
看完技術架構,再看一下基於架構的迭代問題,可以看出 CODING 每天的迭代工作量是很大的,我們每天大概是會新增 200 多個需求,100 多名工程師進行研發,合併 50 多次 MR,但是由於我們的業務是分成多個部門進行研發,如果一個部門的業務 Staging 驗收失敗,可能會導致我們在整個產品迭代部署失敗。

回顧一下架構和迭代的主要痛點,第一個是迭代慢,二是編譯構建慢,三是難以擴展,四是穩定性慢。
在這裏插入圖片描述
帶着問題來看一下微服務架構的主要定義,我把馬丁的關於微服務的定義重點圈出來,我對它的理解是我們需要有一種方法論去切分我們單體的服務,使每個微服務的數據獨立不共享,可獨立構建和部署,並且構建和部署應當有一套自動化的工具來加速整個構建和部署的過程,也就是 CI/CD 和 DevOps。介紹完微服務的定義,大家不難看出微服務架構是用以業務變得複雜的手段,團隊規模擴大後,我們將複雜的業務做出合理的拆分,從而方便各個業務獨立部署,獨立技術架構演進的這麼一個技術架構解決方案,也是我們解決之前問題的架構解決方案。
在這裏插入圖片描述
介紹完微服務,可以清晰地看出 CODING 的微服務改造整體方案出來了,我們的整個改造是開源方案爲主,避免自己造輪子去蹚一些沒有必要的業務上的雷。第二是我們會聚焦核心目標做必要拆分,我們不會一來把所有的單體業務全部拆分爲微服務,我們還是按照一個節奏、步驟去增量改進。第三點是兼容原有架構,技術選型對原有技術架構我們是無侵入、可逐步地將所有的應用拆分成微服務,並且線上用戶沒有感知。第四點是 DevOps 的部分,我重點把 ops 做了顏色上的區分,就是在強調我們在做微服務拆分的時候有 50% 的架構都放在了可運維架構上面。

二、微服務架構落地方案

微服務架構的落地前期主要關注兩個方面,第一方面是如何拆,第二方面是微服務的技術架構選型,主要是兩方面的技術架構選型,一是基礎設施層,另外一個是應用層選型。

首先看一下微服務拆分,微服務拆分是一個業務和組織架構強關聯的問題,同一個公司不同的業務階段不同組織架構拆分的方案也不相同,微服務的拆分是否合理,直接決定服務之間的通訊次數、分佈式事物,以及後期業務演進的便利性。
在這裏插入圖片描述
簡單通過一張圖來看一下,如果說拆分粒度過小,服務的 RPC 和分佈式事務都可能導致性能嚴重下降,這也是我在 2017 年在北京第一次做創業的時候,我當時犯的一個錯誤,第一次我們把一個電商的微服務拆分得非常細,幾乎是可以理解成按照表的維度去做了微服務的拆分,帶來的結果就是服務與服務之間的通訊非常消耗性能,分佈式事務非常之多。如果是拆分粒度過大,就起不到業務的獨立演進的目的。

在介紹微服務拆分之前,我覺得有兩個大的方法論或者說結論需要跟大家分享,第一個是 DDD,由於時間關係,我們在會上理解到 DDD 是一種架構設計的方法,是我們劃分業務便捷有效保證微服務高內聚低耦合的方法論就可以了。
在這裏插入圖片描述
我們在具體落地的過程中,是通過一個事件風暴的會議來實現聚合和限界上下文,這是我們需要在 DDD 裏面理解的兩個概念。其中聚合是我們在業務領域的組成部分,在同一個微服務中,而限界上下文是服務邊界和微服務的邊界。

第二個是康威定律,康威定律嚴格來說不是方法論,只是一個結論,在講我們的業務模型往往和我們的組織架構匹配,也和我們的系統結構匹配,而每一個業務部門的業務頂域、技術棧、同對文化的差異,必然導致迭代的頻率、發版頻次的不同,也使得單體應用無法滿足公司組織架構的升級,同時也意味着微服務拆分的必然性。
在這裏插入圖片描述
這張圖是 CODING 最後的單體應用拆分方案,我分成了橫向和縱向兩個部分,可以看出我們首先是由於部門之間業務不同,對於獨立部署是剛需,所以我們先進行了部門級別的微服務拆分。在部門內部,我們是根據 DDD 的設計方法劃分業務與業務之間的邊界,形成最終的拆分方案。右邊的圖是我們拆分之後的微服務概要的分佈圖,可以看出拆分之後我們是每一個微服務技術架構可以獨立演進,業務高度聚合,可獨立構建和部署。

看完拆分方案,我們一起來看看技術架構,主要是兩個部分,第一個是基礎設施層,一個是應用層。首先是基礎設施層,我們最後選用的方案是 Service mesh+K8s,我把 springcloud 放在這張圖上面,不是說 springcloud 本身是一個基礎設施層的解決方案,是因爲我們在做技術選型的時候,實際上是用 springcloud+K8s 和 Service mesh+K8s 做了一個對比。其實嚴格來說,兩者重點的區分都是對架構的侵入性和具體實現語言的無關,以及今後我們架構演變的便利性,所以我們最終選擇的方案是 Service mesh。

其實 springcloud 這幾年的發展可以分爲三個階段,第一個是大量整合 Netflix 的一些開源組件;第二個階段是由於 Netflix 迭代速度可能滿足不了 springcloud 社區對於組件升級的需要,springcloud 自己造了一些輪子,比如 spring gateway 這樣的東西。第三個階段是隨着國內對微服務應用技術越來越多,可以看到一些開源的大廠,比如說阿里,他們做了一些開源的貢獻,有很多組件相繼出來。但是對我們而言,對於架構的無形入侵是我們做技術選型最重要的一點,所以我們最終選擇是在基礎設施層解決微服務的網絡治理的問題,所以我們選擇的是 Service mesh,具體來講我們選擇的是 LINKERD2。

接着看一下應用層,可以看出我們應用層的技術選型基本上是圍繞兩件事情來做的,一個是流量的管理,第二個是服務的治理。第一個主要是通過 spring cloud gateway 和 Apollo 的配置中心和 Hystrix 來完成。可以看到由於我們網絡的管理,下沉到了基礎設施層,所以我們這一層沒有服務和網絡相關的中間件。

首先看一下流量管理是怎麼做的,首先講講我們流量是怎麼從外部進入內部服務器的,我們這邊先是在用雲服務器的負載均衡功能將流量打到,雲廠商提供的負載均衡的功能,將流量打到了雲服務器的 Nginx,再有 Nginx 做反向代理到多個實例的網關做 HA。我們這邊對網關組件定義的功能主要是鑑權、認證、動態、路由,跟安全相關的東西,比如說IP白名單功能,比如說限流。
在這裏插入圖片描述
還有一個比較重要的特性是如何監控和報警我們的 API 服務,我們選用的方案是 Hystrix+Promethus,由於時間關係,如果大家對這個本身的技術選型或者說有架構上的疑問,我們可以放在會後講完之後提問環節一起聊一聊。

再看一下服務治理,目前的註冊和發現是依靠 K8s 的 EDCD 來完成,每一個 K8s 的節點都會註冊上去,K8s 的網絡會複製到集羣中間的節點到節點的網絡羣。另外我們調用的方式是走的 GRPC,目前只支持重設和負載均衡,具體是依靠 LINKERD 去做了網絡流量的劫持去完成這件事情。目前 GRPC 的調用還不支持熔斷和降級,我們目前在做整合的過程中。我列了應用部分我們關注的微服務架構問題集,以及我們的選型方案給大家,有興趣的朋友可以問我要這張截圖。

我想補充一點,微服務的拆分不可能是一次做完,架構改造不可能一蹴而就,我們的經驗是先確定最緊急、最重要的業務拆分需求,以此爲根,將業務依賴的技術服務和應用組件先剝離出來,作爲微服務第一期的上線內容,重點是驗證微服務的基礎設施、應用層架構拆分方案的可行性。當然各種灰度方案是有必要做的,只有第一步的象限走穩,後期的逐步拆分纔不會出太大的問題。前期我們做微服務架構改造的時候,也犯了一些錯誤,我們是將產品迭代和微服務架構改造分爲兩件事情在做,我們兩個方向分別去推進,會犯的一個比較大的錯誤或者是問題是,我們需要不停地從主代碼裏面去合併代碼到拆分的工程裏面去。其實這個直接會導致我們的拆分工作量越來越大,問題會越來越複雜。後來直接導致我們拆分的項目改造的信心帶來巨大的打擊。

說完微服務的技術架構,我們再一起看看如何去做本地開發環境。目前我們的業務是由 100 個左右的微服務組成,很明顯開發服務不可能全部形成微服務,因爲就算服務 0.5G 的內存佔用也需要 50 個淨內存,我們需要一個 K8s 集羣環境部署全量 Master 版本的微服務,本地開發使用 Telepresence 提供的網絡代理和轉發機制,將本地的微服務新增或者替換到對應的 K8s 集羣環境中去,就可以方便地完成本地的開發和測試工作。
另外,我們也可以通過這個機制去做部門級別的微服務測試工作。

Telepresence 乾的事情是它會將自己以一個 pod 節點的方式注入 K8s 的集羣裏面去,這個 pod 節點具體乾的事情就是網絡代理和轉發的事情,會將集羣的流量達到開發者本身的流量,開發者可以通過流量的獲取去做本地的功能調試這麼一件事情,其實這個對於一個微服務的本地開發或者是 K8s 的運行環境的開發來說,是非常重要的一件事情。

三、DevOps 之於微服務

剛纔我們介紹瞭如何拆分微服務以及技術架構的基礎設施和應用層的一些技術選型,也介紹了本地開發環境的搭建方式,最後我們一起來看看 DevOps 爲什麼對微服務如此重要。
在這裏插入圖片描述
首先分享一下什麼是 DevOps,其實 DevOps 的核心概念是打通開發和運維的信息邊界,使它們的認知和目標一致,最後使得它們的工具一致、環境一致,從而保障我們的迭代速度和修復問題的能力,從定義上看,DevOps 包含文化的建設和工具的建設兩個部分,文化的建設比較抽象,我們就不展開說。我們今天重點介紹一下工具的重要性,也就是自動化的重要性。

首先看一下自動化構建和自動部署,在 2019 年微服務改造過半之後,CODING 每天需要構建 20 多次完成 50 多次部署,這跟最開始可能一天我們連一次版本都不能發佈的數量變化是非常巨大的。假如這些事情都是沒有自動化構建和部署的支持,光是這麼一個事就是難以想象的工作量需要極大的團隊來維護整個 CI/CD 這件事情。

我們來看一個運維方面的問題,分佈式追蹤,可以想象一下如果線上出了問題,我們需要在幾百個服務實例中找到出錯的服務,可能你還要找到服務裏面,還有 10 個、20 個實例,你要具體定位到哪個實例出了問題,如果沒有分佈式,這是無法想象的事情。但是如果我們有分佈式追蹤的技術,我們現在用的是 opencensus 這件事情,這個排查可能分鐘級別就能做完。

最後不得不提起,CODING 做的就是 DevOps 全流程管理的事情,將我們的代碼從管理到需求管理、自動構建、自動部署全流程打通,極大加速了我們微服務項目迭代的過程。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章