天天看點

【微服務理論】微服務概覽

為什麼要學習架構?

因為架構思路是編碼的基石,如果腦海中沒有架構思路,編碼就是一葉障目,看不到全局也就不可能寫出好的代碼。先别急着撸代碼,先看看理論,有個大緻的概念。

原理可能看看就能懂,但是隻有經曆了實踐,體會了痛點,才能了解和吸收。

當下網際網路行業的火爆,使用者量的激增,讓各大公司開始考慮擴容和重構,微服務是首先引入眼簾的。然而據我所知,國内不少中小規模的技術團隊對微服務的概念都不甚了解,對該不該引入微服務也不置可否。還有一些技術團隊,沒有考慮實際業務場景,隻是為了追求技術熱點,盲目引入微服務,但又缺乏相應的技術掌控能力,最後影響了業務的穩定性。

一、架構選型

組織溝通方式決定系統設計。

一定要根據自己的公司體量、業務形态來選擇架構,好的架構都是一步步演進過來的。不要過于崇尚新技術、新架構。

如果你不知道目前架構有什麼問題,有什麼痛點,那麼一定無法演進。有很多公司或個人看到微服務很火爆,就開始盲目追求。這樣隻能是緣木求魚。

對于微服務,我隻能說,單挑死無全屍。

微服務的首要問題:

該不該引入微服務

微服務體系需要哪些技術

團隊怎麼演進,怎麼落地

根據康威定律:康威定律

“設計系統的架構受制于産生這些設計的組織的溝通結構。”

每個公司的組織架構不同,則會演進出不同的架構。這個很關鍵,後面會反複提到。

比如你的公司是垂直架構,那就是遞進關系,隻有一條線:後端--前端--測試--運維,這樣開發過來,最後找問題肯定是反向來的。

如果你的公司是水準架構,那就是分布式關系,比如:

遊戲部+視訊部+直播部----大後端(中台),那麼你的架構一定是分布式的,并且做了服務拆分,将公共邏輯做成了服務。

那麼,有銀彈麼?沒有!

就像阿裡為什麼要建立中台又拆?隻有不斷的業務改進和架構演進,一切都是為了更好地服務業務,減少開發成本。

是以:

架構的演進一定是源于痛點。

那麼,我們來講講痛點。

二、單體架構,巨石架構

在開聊微服務之前,我先要你和介紹下單體應用。如果你不知道單體應用的痛,那也不會深刻了解微服務的價值。

當公司團隊規模很小的時候,單體應用是最好的選擇。主要模式有:LANMP(Linux + Apache或Nginx + MySQL + PHP)和MVC(Spring + iBatis/Hibernate + Tomcat)兩種。

其優點是學習成本低,開發上手快,測試、部署、運維也比較友善,甚至一個人就可以完成一個網站的開發與部署。

1-4人小團隊首選,放開膀子就是撸。

别上來就微服務,幾個開發人員的小公司,去追求微服務、去追求中台架構,這是追求完美嗎?不是,是找死。

<code>​開發簡單:​</code>

隻有一個git,下載下傳部署調試都很友善。

很容易看到全貌,所有的代碼都在這裡了。

​<code>​易對應用程式進行大規模修改:​</code>​

​<code>​測試相對簡單直覺:​</code>​沒有服務間的聯調,沒有多級調用。

​<code>​部署簡單明了:​</code>​隻有一個應用,扔上去執行就OK了。

​<code>​橫向擴充不費吹灰之力:​</code>​直接運作多個執行個體,開負載均衡即可。

【微服務理論】微服務概覽

應用複雜,​<code>​耦合性高​</code>​。

導緻了重構困難、難以靈活性開發,一崩則全崩。牽一發而動全身。

難以擴充,可能久了就誰都不敢動了。新同僚一來需要閱讀大量代碼,學習成本極高。如果相關負責人離職,那将是雪崩效應。

開發困難

​<code>​IDE卡​</code>​,代碼都在一起,當然卡。

​<code>​編譯慢、啟動慢​</code>​。當單體應用的代碼越來越多,依賴的資源越來越多時,應用編譯打包、部署測試一次,甚至需要10分鐘以上。

<code>​架構更新困難​</code>​,隻能長期依賴某個可能已過時的技術棧。

更新就隻能全升,不能有針對性地利用語言優勢。

<code>​團隊協作開發成本高​</code>​。

早期在團隊開發人員隻有兩三個人的時候,協作修改代碼,最後合并到同一個master分支,然後打包部署,尚且可控。

但是一旦團隊人員擴張,超過5人修改代碼,然後一起打包部署,測試階段隻要有一塊功能有問題,就得重新編譯打包部署,然後重新預覽測試,所有相關的開發人員又都得參與其中,效率低下,開發成本極高。

如果分了團隊開發子產品,團隊之間的時間安排會不一緻,A團隊的代碼很可能對B團隊的代碼産生影響。

​<code>​無法隔離:​</code>​如果有一個大bug,記憶體洩漏、DB打爆,都是噩夢。

【微服務理論】微服務概覽

三、什麼是服務化

最開始的啟發來源于一本書《The Art of Scalability》,即《可擴充性的藝術》,探讨了現代企業的可擴充 Web 架構、流程群組織。

裡面提到了三種擴充方式:

【微服務理論】微服務概覽
【微服務理論】微服務概覽

分别是:

<code>多個執行個體的負載均衡</code>:單體+負載均衡(随機算法)

【微服務理論】微服務概覽

<code>根據請求的屬性路由請求</code>:單機+負載均衡(雜湊演算法)

【微服務理論】微服務概覽

<code>根據功能拆分業務</code>:即服務。每個服務都是由一組專注的、内聚的功能職責組成。

【微服務理論】微服務概覽
圍繞業務功能建構的,服務關注單一業務,服務間采用輕量級的通信機制,可以全自動獨立部署,可以使用不同的程式設計語言和資料存儲技術。

我們将單體應用中的邏輯分離,單獨成立一個項目,獨立開發、測試、上線、運維,然後将程序間調用變成遠端RPC調用,各個子產品之間不耦合,可以交給不同的團隊管理,還可以根據各個子產品的特點選擇不同的語言。這樣就可以解決單體應用膨脹、團隊開發耦合度高、協作效率低下的問題。

【微服務理論】微服務概覽
什麼東西過大,解決的最好辦法就是把它變小。

分而治之,化繁為簡。

在我看來,微服務也是分級别的。也就是微的程度。

比如可以先按大的邏輯拆分,用電商舉例,商品展示、購買、物流這樣分。

也可以商品服務、訂單服務、支付服務等這樣分。

縱向拆分:從業務次元進行拆分。比如可以先按大的邏輯拆分,用電商舉例,商品展示、購買、物流資訊。

橫向拆分:從公共且獨立功能次元拆分。标準是按照是否有公共的被多個其他服務調用,且依賴的資源獨立不與其他業務耦合。比如商品服務、訂單服務、支付服務、評價服務等。

【微服務理論】微服務概覽

差别是什麼?

前一種隻是按接口分,我把展示的接口都放到一個單體寫,那樣這個單體挂了,購買的人不受影響。

問題就是公共子產品(鑒權、底層方法)我要寫多套。

适用于中型團隊,因為公共子產品也不是天天改。

最大程度将業務耦合性降低,A子產品挂了不影響B子產品,而且子產品可以配置設定給不同的人,單獨治理。 線下麻煩點,但是線上穩定點。

舉例:賬号子產品,此時可能是每個單體裡面都有一套賬号資料生成代碼,然後用同一個git維護,一旦更新了就所有單體都要更新。

盡管也是子產品化邏輯,但是最終它還是會打包并部署為單體式應用。

代碼備援嚴重。

單機扛不住隻能上負載均衡,查日志可能要查多台機器。更新也是,要批量上代碼。

資料庫難以隔離,尤其是使用者這種量最多的資料,可能一個bug導緻全盤慢。

故障無法轉移,A機器挂了, B機器的代碼是一樣的,基本也會挂。

影響的是一個整體業務,無法降級,無法熔斷。挂就是一個業務挂。

相似點:

都是特定的風格架構;

都以一系列服務方式組織系統;

不同點:

完全不同的技術棧(微服務架構采用輕量級、開源技術以及啞管道通信);

處理資料方式不同(微服務架構有自己的資料庫);

服務尺寸、規模不同(微服務架構中的服務相對較小);

通信方式不同,SOA采用了ESB企業總線之類的重量級通信方式。

【微服務理論】微服務概覽

另一種就是按子產品分,或者叫按資料分,這才是真的微服務。

​<code>​什麼是微服務​</code>​:圍繞業務功能建構的,服務關注單一業務,服務間采用輕量級的通信機制,可以全自動獨立部署,可以使用不同的程式設計語言和資料存儲技術。

重點:每個服務都有自己資料模型和資料庫。

隻有獨占DB,才能談隔離,才能有針對性地擴縮容、上叢集。

适用于大型公司,業務量很大,每個子產品都是一個小團隊負責。

最大程度減少溝通成本。

當人員數量上來後,最大的消耗并不是編碼時間,而是溝通時間。

舉例:我将賬号集中到一個服務,所有人需要賬号資訊都找我來拿,然後我這邊用負載均衡、叢集保證我的高可用,如果有人要更新使用者資料,要我走我的接口,要麼走我的消息隊列,我來維護賬号資料的一緻性。

圍繞業務或者資料建構,服務關注單一業務。服務間采用輕量級的通信機制,可以全自動獨立部署,可以使用不同的程式設計語言和資料存儲技術。微服務架構通過業務拆分實作服務元件化,通過元件組合快速開發系統,業務單一的服務元件又可以獨立部署,使得整個系統變得清晰靈活。

小即是美:小的服務代碼少,bug 也少,易測試,易維護,也更容易不斷疊代完善的精緻進而美妙。

單一職責:一個服務也隻需要做好一件事,專注才能做好。

一個服務隻做一件事

一個包隻做一件事

一個函數隻做一件事

錯誤例子:Common  utils ,最後就隻是垃圾桶。

盡可能早地建立原型:盡可能早的提供服務 API,建立服務契約,達成服務間溝通的一緻性約定,至于實作和完善可以慢慢再做。

可移植性比效率更重要:服務間的輕量級互動協定在效率和可移植性二者間,首要依然考慮相容性和移植性。

【微服務理論】微服務概覽

Fred Brooks 在30年前寫道,

“there are no silver bullets”。

但凡事有利就有弊,微服務也不是萬能的。

服務的拆分與定義是一項挑戰;

沒有具體的、良好的算法可以完成拆分工作,這讓服務的拆分更像一門藝術。

如果拆分的不好,會成分布式單體,會包含單體和微服務兩者的弊端。

分布式系統帶來各種複雜性,使開發、測試和部署變得困難;

跨服務的事務和查詢。

資料一緻性。

需要高度自動化。

需要統一的日志采集。

當部署跨越多個服務的功能時需要謹慎地協調更多開發團隊;

需要根據服務依賴來制定開發計劃。

需要制定統一的通訊協定。

開發者需要思考到底應該在應用的什麼階段使用微服務架構;

初創公司應該從單體開始。

測試困難

不知道是代碼的bug還是環境的bug。

連鎖反應

上遊(調用者)寫了個for循環,給下遊(提供者),然後下遊再給他的下遊,可能就指數級放大了。

需要添加限流、熔斷等政策。

依賴關系複雜

服務都成了子產品化,彼此之間的依賴關系是極其混亂的,如果不用工具,很難維護調用關系。

​<code>​這樣帶來什麼問題​</code>​:

問題1:for循環點查,qps被成倍放大。一個請求到了下遊可能就成了100個。

問題2:串行請求,慢,而且不做降級就會直接逾時導緻500。

問題3:測試困難,不是代碼的問題,而是部署的問題。

問題4:維護困難

• 日志檢視,這麼多台機器(或目錄)。

• 聯調:不知道是哪個環節慢。

• 報警:哪一環被打挂了也不知道。

​<code>​解決qps放大:​</code>​

粗粒度API,批量傳回多個使用者的中繼資料。

并行請求,多協程請求多個服務節點,再組裝結果。

既然這麼多人選擇微服務,肯定是利大于弊的。

使大型的複雜應用程式可以持續傳遞和持續部署

自動化測試—-持續傳遞和持續部署

獨立部署

開發團隊自主且松散耦合

每個服務都相對較小并容易維護;

IDE快,啟動快。

提高調試、部署等環節效率。

拆分後,代碼量少了, bug也更好發現。

減少了溝通成本,每個人維護好自己的服務即可。

服務可以獨立部署;

服務可以獨立擴充;

有針對地選擇伺服器。

微服務架構可以實作團隊的自治;

每個團隊可以有自己的技術和管理方法。

更容易實驗和采納新技術;

友善試錯和疊代。

更好的容錯性;

故障隔離了,程序和資料庫都隔離了。

耦合性極低。(去中心化)

資料去中心化: 獨占DB,減少資料幹擾。以前一個慢SQL打挂全服的情況不會有了。

技術去中心化:想用什麼語言都可以,隻要實作協定即可。便于重構和疊代。

治理去中心化:

​<code>​原子服務​</code>​:一個服務隻做一件事情。

​<code>​獨立程序​</code>​:獨立程序、獨立機器、獨立釋出。

​<code>​隔離部署​</code>​:每個服務之間獨立部署,可以避免互相影響,并且和按需進行配置設定資源,節省成本 。

【微服務理論】微服務概覽

四、實作微服務

微服務這麼好,我們該怎麼實作它呢?

傳統實作元件的方式是通過庫(library),庫是和應用一起運作在程序中,庫的局部變化意味着整個應用的重新部署。

通過服務來實作元件,意味着将應用拆散為一系列的服務運作在不同的程序中,那麼單一服務的局部變化隻需重新部署對應的服務程序。

我們用 Go 實施一個微服務:

kit:一個微服務的基礎庫(架構)。

service:業務代碼 + kit 依賴 + 第三方依賴組成的業務微服務

rpc + message queue:輕量級通訊

本質上等同于,多個微服務組合(compose)完成了一個完整的使用者場景(usecase)。

無自動化不微服務,自動化包括測試和部署。單一程序的傳統應用被拆分為一系列的多程序服務後,意味着開發、調試、測試、監控和部署的複雜度都會相應增大,必須要有合适的自動化基礎設施來支援微服務架構模式,否則開發、運維成本将大大增加

基建搭建好:消息隊列、日志采集、容器編排等。​<code>​容器化是微服務的基石​</code>​。

文檔寫好,gRPC代碼即文檔。

自動部署,CICD:Gitlab + Gitlab Hooks + k8s

染色釋出,友善開發和壓測。

監控體系:k8s,以及一系列 Prometheus、ELK、Conrtol Panle

Testing:測試環境、單元測試、API自動化測試

【微服務理論】微服務概覽

著名的 Design For Failure 思想(所有依賴的東西都會崩)

微服務架構采用粗粒度的程序間通信,引入了額外的複雜性和需要處理的新問題,如網絡延遲、消息格式、負載均衡和容錯,忽略其中任何一點都屬于對“分布式計算的誤解”。

隔離

逾時控制

負載保護

限流

降級

重試

負載均衡

魯棒是Robust的音譯,也就是健壯和強壯的意思。 它也是在異常和危險情況下系統生存的能力。

比如說,計算機軟體在輸入錯誤、磁盤故障、網絡過載或有意攻擊情況下,能否不當機、不崩潰,就是該軟體的魯棒性。

所謂“魯棒性”,也是指控制系統在一定(結構,大小)的參數攝動下,維持其它某些性能的特性。

一旦采用了微服務架構模式,那麼在服務需要變更時我們要特别小心,服務提供者的變更可能引發服務消費者的相容性破壞,時刻謹記保持服務契約(接口)的相容性。

伯斯塔爾法則伯斯塔爾法則:

Be conservative in what you send, be liberal in what you accept. 發送時要保守,接收時要開放。

按照伯斯塔爾法則的思想來設計和實作服務時,發送的資料要更保守,意味着最小化的傳送必要的資訊,接收時更開放意味着要最大限度的容忍備援資料,保證相容性。

既然分了部門。語言、習慣等都會有很多不一樣,是以要多做相容,多寫文檔(gRPC代碼即文檔)。

所有依賴的東西都會崩。

五、微服務的政治

想要推行一種新的架構,都是困難的,畢竟誰也不想做改變。

銀彈現象:

過熱期(迷戀和崇拜)— 低谷期(失望)— 成熟期(生産力的高地,理性地使用)

理性地看待新技術。

騎大象的人:大象代表思維中情緒化的部分,它完成了絕大部分決策。騎大象的人代表理性的部分,用來對大象的決策進行判斷。

而架構的改變也必然會帶來組織架構的改變。

比如以前,後端開發隻是按功能大緻分一分,誰寫的就一直維護那一塊,然後寫完了就釋出測試,然後打包給運維上線。

但是一旦線上有問題的時候,隻能運維先看伺服器有沒有問題,沒有問題就開始搖後端負責人,然後負責人大緻看一下,看不出來就喊對應功能的負責人。

有的甚至連日志在哪裡看都不知道,畢竟不知道運維怎麼部署的。

現在轉為了微服務,大家自己負責這個子產品的開發、單元測試、運維部署、監控,自動化部署,日志采集也是統一的。

You build it , you run it 運維隻需要提供好用的工具,測試隻用黑盒測試,測使用者場景和UI。

這樣就形成了一個閉環團隊,而且可擴充性大大提升。

總結

沒有最好的架構,隻有最适合自己的架構。根據自己的業務、團隊來定制架構,能快速傳遞、快速疊代、持續重構的架構,就是好架構。

第一,要記住微服務不是解決所有問題的萬能"銀彈"。

第二,編寫整潔的代碼和使用自動化測試至關重要,因為這是現代軟體開發的基礎。

第三,關注微服務的本質,即服務的分解和定義,而不是技術,如容器和其他工具。

第四,確定你的服務松耦合,并且可以獨立開發、測試和部署,不要搞成分布式單體(Distributed Monolith),那将會是巨大的災難。

第五,也是最重要的,不能隻是在技術上采用微服務架構。擁抱 DevOps 的原則和實踐,在組織結構上實作跨職能的自治團隊,這必不可少。還必須記住∶ 實作微服務架構并不是你的目标。你的目标是加速大型複雜應用程式的開發。

當問題足夠大、有足夠多的不确定性因素時,人們習慣把大的問題拆分成小的問題,通過分割、抽象和重用小而可靠的功能子產品來建構整體的方案。

但是當這些小的、可重用的部分越來越多時,又會出現新的問題。

繼續閱讀