微服務通訊的設計模式
https://mp.weixin.qq.com/s/zH1AbVmeB40MiiGXxQRnNQ
在我的上一篇部落格中,我談到了微服務的設計模式。現在我想更深入地探討微服務架構中最重要的模式:微服務之間的相互通訊。我仍然記得我們過去開發單一應用時通訊是一項艱鉅的任務。在那時我們必須小心的設計資料庫表和物件模型對映之間的關係。而現在在微服務中,我們已經將它們分解為獨立的服務,並建立網格來彼此通訊。讓我們來談談迄今為止為解決這個問題而發展起來的所有通訊方式和模式。
許多架構師已經將微服務之間的通訊劃分為同步和非同步兩種模式。讓我們一個一個來介紹。
同步模式
當我們說到同步時,意思是客戶端向服務端發出請求並等待其響應。執行緒將被阻塞,直到它接收到返回。實現同步通訊最主要的協議是HTTP。HTTP可以通過REST或SOAP實現。現在REST在微服務方面發展迅速並超越了SOAP。對我而言兩者都很好用。
現在讓我們討論同步模式中的不同的工作流、用例,我們面臨的問題以及如何去解決。
1. 先從一個簡單的例子開始。你需要一個服務A來呼叫服務B並等待實時資料的響應。這是實現同步的一個很好的選擇,因為不會涉及到下游服務。如果使用多個例項,除了負載均衡之外,你不需要為這個用例實現任何複雜的設計模式。
2. 現在讓我們把它變得更復雜一點。服務A為實時資料呼叫多個下游服務,如服務B、服務C和服務D。
-
服務B、服務C和服務D都必須按順序呼叫——當服務相互依賴以檢索資料,或者是有一個事件序列的功能需要被執行,就會出現這種情況。
-
服務B、服務C和服務D可以並行呼叫——這種場景被使用在服務彼此獨立或服務A可能扮演協調者(Orchestrator)角色時。
這會為通訊帶來複雜性。讓我們一個一個地討論。
緊密耦合
服務A將與服務B、C和D耦合。它必須知道每個服務的端點(endpoint)和憑據(credentials)。
解決方案: 服務發現模式 就是用來解決這類問題的。它通過提供查詢功能來幫助分離消費者和生產者應用。服務B、C和D可以將它們自己註冊為服務。服務發現可以在服務端也可以在客戶端實現。對於服務端,有AWS ALB和NGINX,它們接受來自客戶端的請求,發現服務並將請求路由到指定位置。
對於客戶端,有Spring Eureka發現服務。使用Eureka的真正好處是它在客戶端快取了可用的服務資訊,所以即使Eureka伺服器宕機了一段時間,它也不會成為單點故障。除了Eureka,etcd和consul等其他服務發現工具也得到了廣泛的應用。
分散式系統
如果服務B,C,D有多個例項,它們需要知道如何負載均衡。
解決方案:負載均衡通常與服務發現攜手出現。對於伺服器負載平衡,可以使用AWS ALB,對於客戶端可以使用Ribbon或Eureka。
驗證/過濾/處理協議
如果服務B、C和D需要被保護並驗證身份,我們只需要過濾這些服務的某些請求,如果服務A和其他服務使用不同的協議。
解決方案:API 閘道器模式(gateway) 有助於解決這些問題。它可以處理身份驗證、過濾和將協議從AMQP轉換為HTTP或其他協議。它還可以檢視分散式日誌、監控和分散式跟蹤等可觀測的指標(metrics)。Apigee、Zuul和Kong就是一些這樣的工具。請注意,如果服務B、C和D是可管理的API的一部分,我建議使用這種模式,否則使用API閘道器就太重了。下面將要讀到的服務網格是它的替代解決方案。
處理失敗
如果服務B、C或D宕機,服務A仍然有某些功能來響應客戶端請求,就必須相應地對其進行設計。另一個問題是:假設服務B宕機,所有請求仍然在呼叫服務B,並且由於它沒有響應而耗盡了資源,這會使整個系統宕機,服務A也無法向C和D傳送請求了。
解決方案:熔斷器(Circuit Breaker) 和 隔板(bulkhead) 模式有助於解決這些問題。熔斷器識別下游服務是否停機了一段時間,並斷開開關以避免向其傳送呼叫請求。它將在定義的時間段之後再次嘗試檢查,如果服務已經恢復則關閉開關以繼續對其進行呼叫。這確實有助於避免網路阻塞和耗盡資源。隔板模式有助於隔離用於服務的資源,並避免級聯故障。Spring Cloud Hystrix就是做這樣的工作,它適用於斷路器和隔板模式。
微服務間網路通訊
API 閘道器 通常用於管理API,它處理來自ui或其他消費者的請求,並對多個微服務進行下游呼叫並作出響應。但是,當一個微服務想要呼叫同組中的另一個微服務時,API閘道器就沒有必要了,它並不是為了這個目的而設計的。最終,獨立的微服務將負責進行網路通訊、安全驗證、處理超時、處理故障、負載平衡、服務發現、監控和日誌記錄。對於微服務來說開銷太大。
解決方案:服務網格模式有助於處理此類NFRs。它可以解除安裝我們前面討論的所有網路功能。這樣,微服務就不會直接呼叫其他微服務,而是通過服務網格,它將處理所有的通訊。這種模式的美妙之處在於,你可以專注於用任何語言(如Java、NodeJS或Python)編寫業務邏輯,而不必擔心這些語言是否支援所有的網路功能。Istio和Linkerd解決了這些需求。我唯一不喜歡Istio的地方是它目前僅限於Kubernetes。
非同步模式
當我們談到非同步通訊時,它意味著客戶端呼叫伺服器,接收到請求的確認,然後忘記它。伺服器將處理請求並完成。
現在讓我們討論一下什麼時候需要非同步。如果你的應用讀操作很多,那麼同步可能非常適合,尤其是在需要實時資料時。但是,當你處理大量寫操作而又不能丟失資料記錄時,你可能希望選擇非同步操作,因為如果下游系統宕機,你繼續向其傳送同步的呼叫,你將丟失請求和業務交易。經驗法則是永遠不要對實時資料讀取使用非同步,也永遠不要對關鍵的業務交易寫操作使用同步,除非你在寫後立即需要資料。你需要在資料可用性和資料的強一致性之間進行選擇。
有幾種不同的方式可以實現非同步:
訊息
在這種方式中,生產者將訊息傳送到訊息代理,而消費者可以監聽代理來接收訊息並相應地處理它。在訊息處理中有兩種模式:一對一和一對多。我們討論了同步帶來的一些複雜性,但是在訊息傳遞中,預設情況下就會消除一些複雜性。例如,服務發現變得無關緊要,因為消費者和生產者都只與訊息代理對話。負載均衡是通過擴充套件訊息系統來處理的。失敗處理是內建的,主要由message broker負責。RabbitMQ、ActiveMQ和Kafka是雲平臺中最流行的訊息傳遞解決方案。
事件驅動
事件驅動方式看起來類似於訊息傳遞,但它的用途不同。它不會發送訊息,而是將事件細節連同負載(payload)一起傳送到訊息代理。消費者將確定事件是什麼,以及如何對此作出響應。這會更加鬆散的耦合。有下面幾種型別的負載可以被傳遞:
-
全負載 —— 這將包含與消費者採取進一步行動所需的事件相關的所有資料。然而,這使得它的耦合更加緊密。
-
資源 URL —— 這是一個指向代表事件的資源的URL。
-
僅事件 —— 不會發送負載,消費者將基於事件名稱知道如何從其他源(如資料庫或佇列)檢索相關資料。
還有其他一些方式,比如編排(choreography),但我個人並不喜歡。它太複雜幾乎無法實現,只能通過同步方式來完成。
以上就是本部落格的全部內容。請讓我知道你在微服務通訊方面的經驗。
相關閱讀推薦
Istio免費直播課程推薦
本課程來自 IBM 微課程,通過視訊直播的方式幫助您快速瞭解 Istio,每週一期。
-
11月1日 Istio初探
-
11月8日 Istio上手
-
11月15日 Istio的安全管理
-
11月22日 Envoy
-
11月29日 使用Istio來監控和視覺化微服務
-
12月6日 Istio mixer - 基本概念,策略、遙測與擴充套件
-
12月13日 Istio跨雲管理方案解析
-
12月20日 Istio使用案例:Serverless 平臺knative
-
詳情請參考:IBM微講堂之年度大戲《Istio系列》
點選【閱讀原文】跳轉到ServiceMesher網站上瀏覽可以檢視文中的連結。
-
SOFAMesh(https://github.com/alipay/sofa-mesh)基於Istio的大規模服務網格解決方案
-
SOFAMosn(https://github.com/alipay/sofa-mosn)使用Go語言開發的高效能Sidecar代理
合作社區
參與社群
以下是參與ServiceMesher社群的方式,最簡單的方式是聯絡我!
-
加入微信交流群:關注本微信公眾號後訪問主頁右下角有獲取聯絡方式按鈕,新增好友時請註明姓名-公司
-
社群網址:http://www.servicemesher.com
-
Slack:https://servicemesher.slack.com (需要邀請才能加入)
-
GitHub:https://github.com/servicemesher
-
Istio中文文件進度追蹤:https://github.com/servicemesher/istio-official-translation
-
Twitter: https://twitter.com/servicemesher
-
提供文章線索與投稿:https://github.com/servicemesher/trans