歡迎光臨
每天分享高質量文章

微服務框架解決的那些被開發人員忽視的問題

容器、Mesher(Istio等)、微服務共同構成了彈性軟體架構的基礎。圍繞彈性軟體架構的技術創新層出不窮。透過識別這些技術的邊界,能夠幫助開發者更好的進行技術選型,更好的組合不同的技術為產品服務。本文結合作者在 ServiceComb[1] 專案中的實踐,從系統可靠性、運維、軟體工程能力提升等方面,分享一些被開發人員忽視的技術和管理問題。
Mesher無法解決的微服務問題

 

基於元資料的服務治理
Mesher的核心功能是服務發現和服務治理,微服務框架的主要功能也是這兩部分,從功能上看,他們只是工作方式不同。下圖是Istio架構圖[2]: 
可以看出它的服務發現工作在TCP層,在沒有額外應用配置的情況下,svcA對於svcB的瞭解,只有TCP報文裡面的相關資訊,服務發現完成的功能可以簡單的概括為請求hostname為svcB的請求,轉發到svcB的實體,Envoy能夠做的,除了按照一定的負載均衡策略(比如輪詢、權重等)進行路由轉發,不能夠做其他控制,這種情況嚴重限制了Mesher的治理能力。
為了提升治理能力,需要更多的元資料資訊,這些元資料資訊可能來源於微服務之間的協議,比如服務發現可以工作在HTTP層,這樣Envoy就可以讀取cookie資訊,實現灰度釋出;還有些元資料來源於部署檔案,比如在部署svcB的時候,描述這個服務的版本為v1。在“將使用者ID為user1的實體轉發到v1版本實體”這樣一個簡單的灰度場景,就需要用到協議層元資料和部署元資料。
“元資料”的多少定義了Mesher能夠處理的治理能力集合。多數開源的微服務框架,都擁有比Mesher更多的元資料資訊,因此能夠做更多的治理控制。ServiceComb是目前元資料管理最完善的微服務框架,除了微服務描述檔案microservice.yaml裡面定義了微服務名稱、版本號、應用等基本屬性外,還包含介面描述資訊(即透過Open API描述的介面資訊)。ServiceComb能夠基於介面描述資訊做更多的服務治理。 下麵以一個介面相容轉發的場景為例,簡單介紹下契約在服務治理方面的作用。
 
ServiceComb基於介面元資料的路由管理
彈性擴縮容、服務永遠線上是微服務的核心價值和特徵。彈性擴縮容意味著通常執行環境一個微服務都會有多個版本,永遠線上則意味著執行環境不可避免的需要考慮多個微服務版本並存的狀況。負載均衡管理器的核心功能是將使用者請求轉發到正確的實體上面去。下麵假設微服務A訪問微服務B。B的實體採用B11、B12、B21、B22這樣的方式描述,比如B11表示微服務B版本1的實體1、B21表示微服務B版本2的實體1、以此類推。
負載均衡策略考慮的是在標的微服務存在多個實體的情況下,採用什麼規則轉發請求,常見的有Round Robin,Rondam和基於權重的負載均衡策略。負載均衡策略的配置一般是針對標的服務進行配置的,ServiceComb允許給每個微服務配置獨立的負載均衡策略:
  1. servicecomb:
  2. loadbalance:
  3. B:
  4. strategy:
  5. name: RoundRobin
介面相容是微服務管理裡面非常常見的問題,雖然可以透過管理要求,讓開發者符合一定的規則,比如:
  • 不允許刪除介面

  • 不允許修改介面原型定義

  • 只允許新增介面,或者對老介面的bug進行修改

 

但是微服務處理請求轉發仍然面臨問題,比如B2相對於B1,新增了介面op2,也就是B11,B12存在介面op1,B21、B22存在介面op1、op2,當A請求op1的時候,可以將請求轉發給B11、B12、B21、B22,當A請求op2的時候,只能將請求轉發給B21、B22。負責均衡器需要透過契約識別微服務B的哪個實體具備op1和op2。有了契約,這個轉發過程是自動完成的,將開發者從處理介面相容場景下的轉發問題中解放出來。
在修改介面語意的情況下,這種情況會稍微變得更加複雜一點。比如B1的op1介面存在bug,修複後,升級到B2,升級後,期望A對於B的訪問,都到B2,而不到B1。這個時候,就需要根據灰度規則手工引流。基於契約,CSE能夠允許開發者基於請求引數定義轉發規則,比如:
  1. servicecomb.darklaunch.policy.B={"policyType":"RULE","ruleItems":[{"groupName":"test","groupCondition":"version=2","policyCondition":"operation=op1","caseInsensitive":true}]}
上面的配置,將Operation引數值為op1的請求,轉發到微服務B的版本2實體上去。其中Operation通常是介面引數名稱,用於將介面引數值不同的請求轉發到不同的實體,比如將userid=Chengdu的請求,轉發到B2。ServiceComb對介面引數進行了擴充套件,在InvocationContext裡面的引數名稱也可以用於灰度規則,這樣就實現了在bug修改過程中的對於某個介面的灰度引流。
 
ServiceComb的流量控制和隔離倉
流量控制通常分為客戶端流控和服務端流控。流量控制的難題是無法在產品開發的時候,就預測微服務的處理能力。有些使用者場景,需要根據業務需要,人為降低部分介面的呼叫頻率,以保證重點業務的資源能夠得到及時滿足。ServiceComb基於契約,提供了非常簡單易用的限流配置能力,可以控制具體到介面的流量。
  1. servicecomb.flowcontrol.Provider.qps.limit.[ServiceName].[Schema].[operation]=100
  2. servicecomb.flowcontrol.Consumer.qps.limit.[ServiceName].[Schema].[operation]=100
流量控制機制有很多不足。在微服務架構下,進行全域性限流需要在效能和準確性方面進行折中,所以通常沒有提供全域性限流能力。服務處理能力和執行環境有關係,需要很複雜的併發測試工具,來識別服務的處理能力,針對介面級別的限流策略面臨著在實際環境中無法實施的尷尬境地。進行限流控制的本質原因,是解決計算資源分配的需要,所以從實際微服務實踐中,進行必要的資源隔離,是比限流更有效的手段,透過資源隔離限制資源佔用,不需要對處理能力進行預估,讓業務系統盡可能處理更多的請求而不至於導致全域性崩潰。透過執行緒池進行資源隔離,是非常有效的手段。基於契約,ServiceComb能夠非常方便的給具體介面分配獨立資源。
  1. servicecomb.executors.Provider].[Schema].[operation]: custom-executor
微服務的可靠性和彈性
Mesher技術在服務發現方面提供了一些治理能力,但是Mesher技術並沒有直接讓微服務本身變得更加可靠,也沒有解決微服務自身的彈性問題。
以最常見的服務超時問題舉例。在實際的應用場景中,微服務的各個實體都是對等的,當一個實體出現超時的時候,其他實體一般也會出現超時,這些超時通常是由於使用者請求分佈不均勻,突發流量超出系統處理能力導致的。Mesher的治理能力可以在一個實體出現大量超時的時候,隔離這個實體,但是這種隔離,反而加重了其他實體的負擔,導致系統恢復時間延長。
結合實際情況,解決這類問題通常有幾個思路。一方面是對微服務佔用資源較多的介面,分配獨立的處理資源,不佔用其他能夠快速處理的介面的資源,避免排隊;另外一方面,需要設定合理的佇列大小,對長期排隊的請求進行丟棄。
執行緒池隔離的最早實踐來源於Hystrix,ServiceComb也透過biz-keeper模組集成了相關功能。但是Hystrix具體在使用的時候,存在效能差、呼叫棧過長並隱藏了底層錯誤導致無法定位問題等,Hystrix元件在實際業務系統中無法發揮本來設計上要解決的問題。ServiceComb提供的執行緒池能力,在幾乎不降低業務效能的情況下,提供了很好的資源隔離機制。
執行緒池排隊佇列的大小,是採用執行緒池隔離需要考慮的一個重要問題。設定合理的佇列大小,及時丟棄請求(新來的請求,在隊裡裡面排隊超時的請求)對於系統可靠性和故障快速恢復顯得非常重要。否則突發的大規模請求,可能導致系統癱瘓,長時間無法自動恢復。
Mesher也不能夠使得微服務自身具備彈性。擁有水平擴容能力,是微服務的一個重要設計指標,一個無狀態的微服務具備更好的彈性,而有狀態服務的彈性相對而言就差很多,通常可以採用讀寫分離等技術,保證寫的一致性,而保證讀操作具備彈性。彈性設計是微服務很重要的一個課題,這裡不深入討論,感興趣的讀者,可以閱讀《持續演進的Cloud Native雲原生架構下微服務最佳實踐》作者王啟軍的“可擴充套件設計”系列文章。
此外,微服務開發框架還要能夠處理分散式事務等問題,能夠提供有效手段保證資料一致性。
微服務開發框架在軟體工程能力方面的作用

 

作為開發者,更加關註如何實現功能;作為管理者,關註的問題是多方面的。短期的問題包括軟體的設計規格被滿足,規格能夠被驗證;長期的問題包括開發過程可重覆,軟體系統能夠被繼承、被重用;還包括如何組織能力差異大的開發團隊進行緊密協作,高效分工。滿足這些管理要求,可以進行文化建設、制度建設。但是最好的制度,沒有工具支撐,都會影響開發者效率,最終流於形式得不到正確的實施。
輔助管理的工具有很多,包括專案和缺陷管理工具,測試工具,CI/CD工具等。ServiceComb在微服務框架上也提供了獨特的軟體工程實踐能力支撐。概括起來就是“以契約為中心”,下圖展現了這個工程能力: 
管理、設計環節
微服務的能力全部透過REST介面開放,從管理和設計角度,提供了一個很好的管控點。在實際的專案團隊裡面,需求分析和設計人員首先對微服務的介面進行設計,並建立獨立的Git庫存放介面定義。透過做好Git庫的許可權管理,並將Code Review流程納入介面專案的管控,管理者能夠保證軟體規格是按照設計要求進行的。
ServiceComb開發的微服務,啟動的時候會分析微服務所有的對外介面,並將契約資訊註冊到服務中心,服務之間的呼叫需要嚴格滿足契約的要求,並提供了管理介面,可以方便的查詢契約。
透過靜態的方法管控規格一般是不夠的,管理者還可以使用契約生成測試程式碼,書寫一定的驗收測試用例,或者將契約提交給第三方進行驗收測試。
為了更好的支援微服務介面和微服務實現分離,需要按照一定的目錄規範組織程式碼。《基於CSE的微服務工程實踐-Native API先行[3]》提供了一個可以供開發者參考的專案。
開發、測試環節
基於契約,可以開發程式碼生成工具,生成開發專案或者測試專案。開發者只需要按照介面要求,實現業務邏輯和測試邏輯。
《單體應用微服務改造實踐[4]》裡面提到了自動化測試在保障軟體質量方面起到的關鍵作用,也提到瞭如何透過開發測試微服務進行更好的整合測試。透過工具生成開發、測試專案,使得開發人員能夠在開發業務邏輯的時候,同步開發測試微服務。
部署環節
契約能夠幫助使用者更好的管理能力開放。“API經濟” 開啟了公司能力透過API的方式對外界開放的視窗,很多公司透過提供介面給其他公司使用,並透過計費系統,按呼叫次數或者時長進行收費。能力開放的核心元件是APIG,APIG能夠幫助使用者完成開放介面的配置、計費以及常見的管控,比如流量控制等。有了契約,完成這些配置,不需要人工輸入,只需要將契約匯入,勾選對應介面的規則就完成了能力開放。
治理
談到微服務,就會談到微服務治理。不同的地方對於微服務治理有不一樣的定義。本文認為,保障微服務可靠執行的機制集合,共同構成了服務治理。在比較Mesher和微服務開發框架的章節,已經分析了契約在治理方面的一些能力,這裡不再重覆。
運維
在運維階段,契約仍然發揮非常重要的作用。基於契約,metrics可以生成介面級別的時延分佈資料。
  1. servicecomb.invocation.role=CONSUMER
  2. servicecomb.invocation.operation=[ServiceName].[Schema].[operation]
  3. servicecomb.invocation.status=200
  4. servicecomb.invocation.type=latencyDistribution
  5. servicecomb.invocation.scope=[1,3)
基於契約和metrics資料,可以開發強大的的運維工具,展現系統介面執行狀況,快速查詢介面運維資料。
ServiceComb的metrics資料深入底層執行環境,能夠讀取和統計介面在佇列排隊、業務處理等非常細粒度環節的時延,從而為分析“毛刺”問題提供了資料支援。(“毛刺”是同事在分析效能問題的時候,對於部分請求某些時刻時延偏高,但是又不容易模擬重現現象的生動描述。)
容器、Mesher和微服務的有效配合

 

上面重點討論了Mesher和微服務,容器解決的問題相對來說比較容易理解。容器管理應用的彈性伸縮,在搭建測試環境、快速部署等方面都帶來很大的便利。有很多基於虛擬機器的歷史遺留系統,自身開發了強大的部署管理系統,依然具備生命力,然而容器技術使得這個過程變得更加簡單和標準了。
Mesher無法解決應用自身的可靠性和彈性,然而Mesher在治理能力方面還可以進一步增強。透過擴充套件Mesher的元資料管理能力,Mesher也能夠實現大多數微服務開發框架提供的治理能力。ServiceComb專案最近在討論將基於Go語言開發的mesher專案[5]納入微服務解決方案的一部分,新增加的mesher專案規劃了和Istio的互協作,同時規劃了把介面契約納入元資料管理範圍,以擴充mesher的治理能力。微服務開發框架也沒有能夠完全解決應用自身的可靠性和彈性,很多問題還是需要開發者結合實際情況處理。總體看,Mesher在治理能力方面能夠接近微服務框架提供的能力,而微服務框架可以在解決應用可靠性和彈性方面提供更多的支援。
從當前情況看技術選型,如果專案規模不複雜,或者開發語言統一,可以選擇微服務開發框架,而不選擇mesher技術,微服務開發框架能夠幫助開發者更加靈活的處理業務問題,能力更加成熟,擴充套件性也更好。如果專案規模複雜,涉及多種開發語言,可以選擇將服務發現和治理採用mesher技術承載,具體的開發語言仍然選擇一個合適的微服務開發框架,不啟用對應的服務發現模組。大多數微服務框架都支援去掉服務發現功能,比如Spring Cloud去掉服務發現後,就直接使用spring boot;ServiceComb開發框架去掉服務發現後,就是一個自定義的loadbalance模組,這個模組對任何微服務發現的結果就是一個域名。
Q&A;

 

Q:ServiceComb適合多大的研發團隊使用?或者說多大的業務量可以考慮使用微服務框架?
A:和研發團隊規模沒有關係,實際上小的研發團隊一般都會選擇適合自己的框架,而不是自己研發。專案規模大小更多的影響的是軟體工程過程,即要管控的東西的多少,團隊越大涉及的工具集合也會越多。
Q:微服務是怎麼能夠幫助研發團隊去實現DevOps的?
A:微服務實際上是最適合DevOps的,因為更容易組建小的披薩團隊。DevOps需要更多的工具支撐,今天的內容沒詳細涵蓋這一部分。
Q:COMB支援哪些常見的協議?
A:支援最好的是REST(HTTP/HTTP2+JSON),還支援基於TCP+Protocol Buffers的協議。對於COMB設計感興趣的同學可以閱讀我的部落格。 https://bbs.huaweicloud.com/blogs/1fc9427c088611e89fc57ca23e93a89f
Q:對於大企業的研發團隊和中小企業團隊來講,對採用微服務能夠獲得的收益期望應該是不同的吧?
A:期望上講每個團隊應該都是有差異的。有些期望改善效率,有些期望降低複雜度,有些解決復用問題,有些想加快團隊創新和試錯速度等。因為微服務實施必須有配套的工具集合才能夠更好的管理大規模微服務,所以小團隊在沒有這些工具的時候,實際上在開發過程和部署上和以前的開發樣式並沒有特別大的差別。
Q:Istio已經成為了事實上的Mesh標桿,COMB在功能上與Istio多有重合,你認為COMB前景如何?
A:Istio實際上是支援很多擴充套件的,能夠支援替換Mesher部分。COMB目前的定位並不是取代Istio,而是期望能夠擴充套件其功能。當然mesher還有很多其他功能,可以用於其他Istio不適用的場景。
參考材料:
  1. ServiceComb專案:https://github.com/apache?utf8=%E2%9C%93&q;=servicecomb&type;=&language;=

  2. Istio架構圖:https://istio-releases.github.io/v0.1/docs/concepts/what-is-istio/overview.html

  3. 基於CSE的微服務工程實踐-Native API先行: https://bbs.huaweicloud.com/blogs/7c03a4793cd011e9bd5a7ca23e93a891

  4. 單體應用微服務改造實踐:https://bbs.huaweicloud.com/blogs/17ad483f325f11e9bd5a7ca23e93a891

  5. ServiceComb討論的mesher專案:https://github.com/go-mesh/mesher

 

贊(0)

分享創造快樂