21CTO導讀:微服務架構的目標是幫助工程團隊更快,更安全,更高質量的交付產品,用來觸耦相關服務,從而讓團隊快速迭代,對系統的周邊部分影響很低。
在Medium,我們的技術棧始於2012年的單片Node.js應用程式。我們還創建了幾個衛星服務,但是我們還沒有制定一個系統採用微服務架構的策略。隨著系統越來越複雜,並且團隊不斷的開發,在2018年,我們轉向了微服務。
在本篇文章中,我們分享一下團隊有效實現並避免微服務「綜合症」的經驗。
何為微服務架構
首先,我們來思考微服務之架構是什麼,不是什麼。微服務是拯救那些過載和混亂軟體工程的技術趨勢之一。
在Medium團隊,我們認為它是:
「在微服務架構中,多個鬆散耦合的服務協同工作。每項服務都專注於一個目標,並具有較高的行業和數據之聚合力」。
微服務的設計包括以下三大原則:
1、單一性
每個服務應專注於一個目的並做好;
2、鬆耦合
服務彼此間沒有過多聯繫。對一項服務的修改不需要讓其它服務配合更改。服務之間的通信僅通過公共服務api進行。
3、高內聚
服務封裝了相關的行為和數據,如果我們需要構建一個新特性,所有的修改應該只涉及到一個服務。
微服務設計(建模)三原則
以下介紹微服務建模時,我們都應該遵守這三個設計原則。這是實現微服務架構全部潛力的唯一途徑,錯失任何一個都會成為反模式。
如果不是單一的目標,每個微服務慢慢就會做越來越多的事情,成長為多個「單片」服務。我們不會從微服務架構中獲得所有的好處,它會增加我們的運維成本。
如果沒有做到鬆耦合,對一項目服務的更改就會波及到其它服務,因此我們無法快速並安全的發布更新,這便是微服務架構的核心優勢。另外一個更重要的事情是,緊耦合引發的問題將是災難性的,比如數據不一致,甚至導致數據丟失。
如果沒有高內聚,我們最終還是會得到一個分布式的單片系統,那是一組混亂的服務,必須同時修改和部署才能構建單一功能。由於多個服務協調的複雜性和成本很高,有時要跨多個團隊協調,分布式單片系統通常比集中式單片系統的性能差很多。
微服務其實也並非那麼重要,有如下原因:
1、微服務並不是小數量的代碼行或者「微小」任務的服務。這種誤解來自於「微服務」這個名字。微服務架構的目標並不是讓團隊有儘可能多的小型服務。只要符合上述三項原則,服務就有可能複雜的。
2、一個微服務不是被新技術所組成的服務。儘管微服務架構允許團隊更輕鬆地測試新興技術,但這並不是微服務的主要目標。只要團隊從分離的服務中受益,你就可以使用相同的技術棧構建新服務。
3、微服務並非必須從頭創建服務。如果你已經有一個架構優良的單片應用程式,那麼不用從頭一個個的來構建新服務。可能的策略是,直接從單一服務中提取邏輯。這樣,上面提到的三個原則仍然有效。
一定不要為了構建而去構建新服務,每次我們構建一個新服務時,必須具有明確的產品或者工程價值。
產品價值表現在能給用戶帶來好處,工程價值表現在可以使技術團隊的工作更好、更快,只有價值優於在 Node.js 單片應用中構建時才決定構建新的服務,否則就繼續Nnode.js單片應用中修改。
持久化存儲建模在微服務建模中是一個重要部分,服務間共享持久化存儲實現非常簡單的方式,但危害極大,我們要儘量避免。
持久化存儲涉及到產品實現細節,服務間共享數據存儲就把一個服務的實現細節暴露給了整個系統,如果這個服務修改了數據格式、添加了一個緩存層,其他服務就要跟著做相應的修改,這樣嚴重違背了鬆耦合原則。
如果共享了數據持久化存儲,那麼例如數據的修改、使用等行為就需要多個服務都各自實現,這違背了高內聚原則。如果修改某個行為,其它相關服務都要跟著修改。
在微服務架構中,一個特定類型的數據應該只由一個服務負責,其他服務應該通過API來調用此服務請求數據,或者僅僅是持有數據的只讀副本。
以下我們來看一個實際的例子,比如要構建一個新的個性化推薦服務,需要 Post 表中的數據。
單片的持久化存儲方式:
在單片架構中,個性化推薦服務直接訪問 Post 表,缺點如下:
緩存會變得很棘手,如果推薦服務共享了單體應用的Cache,我們就必須在推薦服務中實現Cache的細節,如果推薦服務使用自己的Cache,當單體應用更新了Post數據時,我們不知道什麼時候使Cache中的數據失效。
如果單體應用決定更換資料庫,例如從DynamoDB換成RDS,那麼就需要重新實現推薦服務中的相關邏輯。
在單體應用中,Post數據涉及到複雜的邏輯,例如如何決定一個Post是否呈現給某個用戶,在個性化推薦服務中就也需要實現這些邏輯。如果單體應用中添加或者修改了邏輯,那麼推薦服務也得跟著變化。
單片服務使用了DynamoDB,那麼推薦服務也就被限制在了這個資料庫,即使這個資料庫並不適合此服務。
在解耦的微服務模式中,推薦服務不再直接訪問Post數據,單片服務負責Post實現細節,而且有多種方案可選。
方案A,由一個 post service 擁有 post 數據,其它服務通過它的API來訪問post數據表。
方案B,當post數據發生更新時,單片服務通過消息隊列服務通知給個性化推薦服務。
方案C,由ETL管道為推薦服務產生post數據的只讀副本。
這3個方案中,個性化推薦服務都可以完全的擁有自己的數據,所以可以靈活的應用,例如Cache的實現、選擇適合自己的資料庫等等。
每個服務應該只關注它自己的工作,最好不要管別的複雜的亂事,比如網絡、通信協議、部署、監控等等,服務管理相關工作應該與服務實現完全解耦。
1)網絡
網絡通信(服務發現、路由、負載均衡、流量等)是運行服務的重要部分,傳統方法是提供公眾語言庫,但是不夠理想,因為應用需要做全部的集成工作和維護工作。
現代化的解決方案是使用 Service Mesh,Medium 使用了 Istio 和 Envoy,構建服務的工程師完全不用關心網絡相關的工作。
2)通信協議
不管你選擇什麼技術棧或語言來構建微服務,選擇一個好的RPC方案是極其重要的,RPC方案需要高效、跨平臺、較小的開發量,Medium 選擇的 gRPC(https://grpc.io)。
目前基於 HTTP 的 REST+JSON 方案非常普遍的。但在 Server-to-Server 的通信的效率卻不是很高,尤其是需要發送大量請求的情況下,而且沒有自動生成的樣本代碼,我們需要手動實現伺服器/客戶端代碼。
3)部署
使用一致的方法來構建、測試、打包、部署、管理所有的服務是非常重要的,Medium 的所有微服務都運行在容器中,使用 Kubernetes 編排管理。
Medium 開發了自己的一套系統,來構建、測試、打包、部署服務,每個服務只需要提供基礎信息,例如監聽埠、build/test/start 命令等,其他事情都由系統來處理。
監控可以讓我們知道系統正在如何工作,當出現問題後可以方便地追蹤問題。監控行為包括日誌、性能指標、儀錶盤、報警等。
Medium 剛開始轉到微服務時,遇到了兩個問題:
第一,由於微服務複雜度高,很難監控,導致系統沒有可監控性。
第二,不同團隊對於自己那塊兒做監控,重複創造輪子,最終導致監控碎片化,碎片化數據很難連接、歸類,可監控性極低。
後來 Medium 使用了 DataDog 服務,實現了自動化儀錶盤、告警、日誌,還使用了 LightStep 來跟蹤系統性能。
5、從開始就避免使用微服務綜合症
微服務不是靈丹妙藥,它能解決一些問題,但同時也創造了一些其它問題,我們將其稱為「 微服務綜合症 」。
如果從一開始不去考慮,那麼這些事情會變得越來越糟糕,如果我們以後再照顧它們會花費更多成本和時間。
以下是一些常見的大症狀,供大家參照:
1、設計不良的微服務造成的傷害大於好處,特別是當你有超過幾個微服務時。
2、允許太多不同的開發語言/技術棧並存,這會增加運維成本,使開發組織分散。
3、將運行服務與構建服務混合在一起,這增加了每項服務的複雜性並減慢了團隊的開發速度。
4、忽略資料庫設計,最終得到只是單一數據存儲的微服務。
5、缺乏可視性,對性能問題或故障難以進行分類。
6、當遇到問題時,團隊傾向於創建新的輪子而不是修復現有服務,即便後者是最好選擇。
7、即使服務是鬆耦合,但是缺乏整個系統的整體畫像也存在極大問題。
技術團隊要經常思考如何做失敗測試、如何很好的解決錯誤。
首要一點是隨時要有面臨出錯的意識。
對於 RPC接口,要在處理錯誤上多做工作。
對於失敗要可監控。
上線新服務時要多做失敗檢測,整理出檢查清單。
構建自動恢復機制。
7、我們應該停止構建單片應用?
伴隨著技術的不斷創新,構建微服務架構變得容易得多。這是否意味著都應該停止構建單片架構與服務?
雖然新技術支持變好,但微服務仍然是高度複雜性和高複雜的架構。
對於小型團隊來說,單一的應用程式通常仍然是更好的選擇。
但是,開始時要創建一種系統化和有成長的預見力,在以後能更容易遷移到微服務架構的單片應用架構。
單片體系結構須確保模塊化,應用上述三個微服務原則(單一性,鬆耦合和高內聚)來構建,除了「服務」外,使用同一技術棧來實現,部署在一起並在同一個容器中運行。
Medium在早期應用中得益於一些較好決策,首先組件高度模塊化,後來即使發展成為一些複雜的應用,包括Web服務,後端服務和離線事件處理、脫機事件處理等,但它們都用完全相同的代碼,這使得業務邏輯很容易抽象為單獨服務,只要新服務提供與原始模板實現相同的API即可。
整體應用封裝了數據存儲層,每種數據類型(例如,資料庫表)都具有兩層實現:數據層與服務層。
所有CRUD操作都由一個數據服務層處理,它封裝了一個特定類型的數據的高級邏輯,並提供公共API。
微服務彼此不共享數據存儲,數據實現細節完全隱藏在代碼的其它部分,這樣創建新服務與處理數據容易也更安全。
單片應用還可以幫我們專注於系統最重要部分,不用從頭開始做微服務設計。
小結
單片的Node.js應用伴隨Medium正常運行了好幾年,隨著項目的複雜度越來越高以及產品快速迭代,技術棧開始系統地採用微服務架構。
即便如此,技術團隊仍然處於這一過程的早期階段,但我們已經看到了微服務的優勢與潛力,它大大提高開發效率,讓人們能夠更大膽思考提升產品,解放軟體工程團隊能夠安全的測試、開發新技術。
編譯:洛逸
來源:Medium技術團隊
地址:https://medium.engineering/microservice-architecture-at-medium-9c33805eb74f