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

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

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

1、單體架構簡介服務器

雖然第一部分是介紹單體架構的主要痛點,可是仍是應該跟你們分享一下,單體應用對於咱們在業務早期,業務處理單一,團隊規模較小,單體應用的中心化處理方案是可以下降團隊的溝通成本,下降架構的複雜度,從而提升研發效率的這麼一個架構。因此是否升級微服務架構,取決於咱們所處的業務階段和組織架構。介紹完單體架構的優點,咱們一塊兒來看看 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% 的架構都放在了可運維架構上面。工具

2、微服務架構落地方案

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

首先看一下微服務拆分,微服務拆分是一個業務和組織架構強關聯的問題,同一個公司不一樣的業務階段不一樣組織架構拆分的方案也不相同,微服務的拆分是否合理,直接決定服務之間的通信次數、分佈式事物,以及後期業務演進的便利性。

 簡單經過一張圖來看一下,若是說拆分粒度太小,服務的 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 的運行環境的開發來講,是很是重要的一件事情。

3、DevOps 之於微服務

剛纔咱們介紹瞭如何拆分微服務以及技術架構的基礎設施和應用層的一些技術選型,也介紹了本地開發環境的搭建方式,最後咱們一塊兒來看看 DevOps 爲何對微服務如此重要。

首先分享一下什麼是 DevOps,其實 DevOps 的核心概念是打通開發和運維的信息邊界,使它們的認知和目標一致,最後使得它們的工具一致、環境一致,從而保障咱們的迭代速度和修復問題的能力,從定義上看,DevOps 包含文化的建設和工具的建設兩個部分,文化的建設比較抽象,咱們就不展開說。咱們今天重點介紹一下工具的重要性,也就是自動化的重要性。

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

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

最後不得不提起,CODING 作的就是 DevOps 全流程管理的事情,將咱們的代碼從管理到需求管理、自動構建、自動部署全流程打通,極大加速了咱們微服務項目迭代的過程。

相關文章
相關標籤/搜索