微服務的服務間通訊與服務治理是微服務架構的實現層面的兩大核心問題。
本文希望通過結合扇貝生產環境中的實踐(百萬日活場景),給大家分享相關的經驗心得。
服務間通訊
從通訊型別的角度看,大概有三種型別:同步呼叫,非同步呼叫,廣播。
在微服務的設計之初要想清楚呼叫關係以及呼叫方式,哪些需要同步,哪些可以非同步,哪些需要廣播,最好團隊內部要有統一的認識。
然後就是要確定好呼叫協議了,例如常見的選擇有:
- 同步呼叫:HTTP REST, gRPC, thrift, etc.
- 非同步呼叫:Sidekiq, Celery, etc. 對應的backend有 Redis, 各類 AMQP 實現, Kafka 等等
- 廣播:各類 AMQP 實現, Kafka,etc.
對於如何選擇,我們需要從很多角度去思考。網上有大量的 "X vs Y"的文章或問答。其實無非就是從幾個角度:效能,成熟度,易用性,生態,技術團隊。我們的建議是:優先選擇社群活躍,以及和自己團隊技術棧相融的。社群活躍的技術往往代表了趨勢和生態,而團隊技術棧的相容性則是能否落地成功的保證。
比如當時扇貝選擇gRPC
作為同步呼叫的介面協議。主要考慮的就是兩點:1. 社群活躍,發展非常迅速;2.基於 HTTP/2,與我們的技術棧相容。
除了選擇協議,更加重要的應該就是介面文件的管理了。最好介面文件和程式碼是強相關的,就像 gRPC 的 proto 和生成出來的程式碼那樣。否則人往往是有惰性的,很有可能程式碼改了文件沒改。
總之,關於服務間通訊,我們需要做好:
- 確定介面規範,什麼用同步呼叫,什麼用非同步,什麼用廣播;同步呼叫用什麼協議,非同步用什麼
- 確定介面協議,以及思考介面文件的管理,介面文件與程式碼之間如何建立強聯絡
服務治理
服務治理是個非常大的話題,真的要鋪開來講,可能幾篇文章的篇幅都講不完。這裡我們想先簡單地看一下服務治理要解決的問題,以及現在的一些解決方案,發展趨勢。
最後以扇貝為例,簡單介紹下在一個真實的百萬日活的生產環境中,服務治理是如何做的。
什麼是服務治理
微服務化帶來了很多好處,例如:通過將複雜系統切分為若干個微服務來分解和降低複雜度,使得這些微服務易於被小型的開發團隊所理解和維護。然而也帶來了很多挑戰,例如:微服務的連線、服務註冊、服務發現、負載均衡、監控、AB測試,金絲雀釋出、限流、訪問控制,等等。
這些挑戰即是服務治理的內容。
現有方案
服務治理的問題由來已久,微服務化盛行之後尤為突出。主流的方案有:基於Spring Cloud或者Dubbo等框架。但是這些方案的問題是:1.對程式碼有侵入,也就意味著,如果想換框架,得改很多東西。2.語言特異性(Java),如果我們用的是 Go/Python,或者我們的微服務不全是 Java,就搞不定了。
Service Mesh
2017 Service Mesh 橫空出世,讓我們眼前一亮。網上有很多關於 Service Mesh 的介紹,大家可以去網上搜一搜。我的理解,Service Mesh 的核心思想就是“代理流量”。Service Mesh通過一個個"代理" 來為微服務轉發/接收所有流量,通過控制這些代理,就可以實現服務連線,註冊,發現,負載均衡,熔斷,監控等等一系列服務治理相關功能,從而微服務的程式碼不再需要服務治理的實現,換句話說,也就是服務治理對於微服務開發者而言是透明的。如下圖所示:綠色方塊為微服務,藍色方塊為 service mesh 的代理,藍色線條為服務間通訊。可以看到藍色的方塊和線條組成了整個網格。這個網路就是 Service Mesh。
目前普遍認為 Service Mesh 有兩代:第一代的 Linkerd/Envoy 和第二代的 Istio/Conduit。第一代相對比較成熟穩定,可以直接用於生產環境,第二代目前(2018年初)都不完善,嚴重不推薦用於生產。
扇貝的 Service Mesh 是基於 Envoy 配合 Kubernetes 實現的。
gRPC 的服務發現,負載均衡和 RateLimit
這一節以扇貝為例,簡單介紹下我們是如何做服務治理的。
首先介紹一些前提:扇貝的微服務全部容器化,編排系統基於 kubernetes
,同步呼叫基於 gRPC
,非同步基於 celery[rabbitmq]
。開發語言以 python3
, nodejs
, go
為主。 Service Mesh 基於 Envoy
總體的方案是:Envoy
以 DaemonSet
的形式部署到 kubernetes
的每個 Node
上,採用 Host
網路模式。 所有的微服務的 Pod
都將 gRPC
的請求傳送到所在 Node
的 Envoy
,由 Envoy
來做負載均衡。如下圖所示:
這裡做一些詳細的解釋。
Envoy
中的Route
類似於Nginx
的Location
,Cluster
類似於Nginx
的upstream
,Endpoint
對應於Nginx
的upstream
中的條目。- 之所以選擇
Envoy
而沒有用Linkerd
,是因為當時Envoy
是對HTTP/2
支援最好的。且資源消耗更少。 - 之所以選擇
Host
網路模式是為了最大化提高效能。 - 對於
Enovy
而言,服務發現就是告訴Envoy
,每個Cluster
背後提供服務的例項的IP(對應於Kubernetes
也就是Pod
的IP)是什麼。 - 最開始服務發現是利用
Kubernetes
的DNS
,因此,在建立Service
的時候,要使用ClusterIP: None
。 - 後來的服務發現是基於
Kubernetes
的Endpoint
API 實現了Enovy
的EDS
(這個專案我們日後會開源到 GitHub 上)。 - 對於
Envoy
而言,實現熔斷,只要實現 rate limit service 就行了。我們基於Lyft/ratelimit 實現的 rate limit service。 - 微服務之間的呼叫情況都可以通過
Envoy
的 statistic API反映出來,所以我們針對 statistic API做服務呼叫的監控報警。 - 同理,呼叫日誌也可以利用
Envoy
的 Access Log 來實現。
未完待續
關於服務治理,我們接下來的文章還會跟大家分享關於DevOps的實踐, 監控報警系統,日誌系統的構建等等內容。最後,如果你也對微服務,k8s, service mesh, devops 感興趣,歡迎加入!
---
歡迎關注我們的 知乎專欄:扇貝技術架構小組