目前大部分的系統架構都是微服務架構,就算沒有註冊中心、服務管理,也肯定是多個服務,單體服務比較少了。
大家平時需要在應用內呼叫rpc介面也比較多,那麼有沒有思考過微服務之間的呼叫和應用內直接呼叫有什麼區別呢?面試時是不是經常被被問到微服務呢,本篇文章針對微服務間的方法呼叫和應用內方法呼叫的有啥區別這個很小的點,談談我的經驗
微服務呼叫特點
先從單體應用說起
單體應用單體引用通過一個服務節點直接組裝好資料,返回給呼叫者。所有的方法呼叫都發生在應用內部。
微服務應用商品詳情服務需要呼叫商品,營銷等多個服務組裝好商品詳情頁的資料
微服務呼叫和應用內呼叫不同點在於它是跨程式的,甚至是跨節點的,這意味著什麼呢
-
使用k8s編排微服務時,我們可以讓不同的服務放在同一個節點的不同docker container上,但是考慮到網路不可靠,和容災,
-
服務之間不可避免會放到不同的節點/機架上,所以下文都以跨節點來討論
意味著兩點
- 對外部有了依賴
- 如果是跨節點,就有了網路呼叫。我們知道網路都是不可靠的
關於網路有幾個著名的錯誤推論
-
The network is reliable(網路是可靠的)
-
Latency is zero.(延遲可以為0)
-
Bandwidth is infinite(頻寬是無限的)
-
The network is secure(網路是安全的)
-
Topology doesn't change(網路拓撲結構不會變)
-
Transport cost is zero(網路傳輸耗時為0)
-
The network is homogeneous(網路是同類的)
我們需要做什麼
存在上述兩個問題後,那麼我們需要在寫微服務間方法呼叫時注意什麼的
對外部有了依賴
微服務架構設計中有一條重要的原則叫嚴出寬進,嚴出意思就是說你提供給其他服務的東西要儘可能的進行嚴格的校驗。寬進就是你呼叫別人的介面要寬容,相容各種情況。比如說你需要考慮別人的節點down了/api超時/api不可用等等因素。
為了解決這個問題,我們必須要針對具體業務,分析依賴型別,是強依賴還是弱依賴,強依賴包裝成自己的服務異常返回碼/或者直接告訴前端呼叫不可用。弱依賴,catch所有異常,無論依賴方發生什麼,不能影響我的介面返回。
此外,我依賴的服務某段時間內介面錯誤率很高,呼叫方還在不停的傳送請求,那麼就會一直得到錯誤的結果,這時候這些請求其實是無效的,所以這時候需要客戶端熔斷,不再去呼叫服務方,給服務方恢復的時間,等過段時間再去重試,發現服務方可用時,再去呼叫。
網路呼叫
網路呼叫是耗時的,所以我們需要利用池化技術,複用連線,比如在單體應用中我們需要與資料庫連線,會利用到資料庫連線池來提高資料操作效率。那麼微服務呼叫也是這麼個道理,我們與其他服務建議http/tcp連線,也需要建立連線池。另外一個服務可能會依賴多個微服務,不能因為和某個服務之間的連線出了問題,影響到與其他服務的連線,所以需要做連線池隔離。
服務間呼叫有可能失敗,所以我們需要有重試機制,比如因為網路抖動引發的超時問題,我們可以通過重試提高API的可用性。
但是思考一下壞的情況,某段時間網路或者服務端真的有問題了。客戶端超時時間設定的很大的話,客戶端等待的時間就會很長,然後再加上重試機制,就會將客戶端的連線佔滿,造成客戶端相關API不可用。
幾個案例
分享幾個微服務呼叫的故障案例,幫助大家進行場景化思考
為啥要分享這些案例呢,因為TMD的這些案例都是血的教訓,造成線上故障,不是我的錯,卻要我背鍋
案例1:
新上線了一個產品功能,需要推廣,放在另外一個流量比較大的產品模組中,展示一些我們產品功能的資料。
出於某種原因,我們的服務mock了rpc呼叫資料,返回null。結果其他服務整個前臺頁面掛了,掛了,掛了。典型的強弱依賴問題,呼叫方沒有處理好依賴型別,明明是一個弱依賴沒有處理,變成了強依賴,造成功能掛了
案例2:
依賴的某個服務需要根據主鍵List來批量查詢,依賴服務內部做分庫分表拆分,升級了sdk
在提供的sdk client中做分表路由,將批量id拆分成N個rpc呼叫。這麼做的原因是防止批量查詢把資料庫連線池打爆。
忽略了網路呼叫案例3
別人調我們的服務的某個介面,這個介面RT(耗時時間)P95 < 30ms。但是客戶端呼叫的超時時間設定成了500ms,在某次不知道是什麼原因的情況下,呼叫方的連線大量block,造成執行緒阻塞,相關API不可用。看服務方監控,該介面返回時間正常,服務方沒有任何異常。
沒有正確的設定超時時間
總結
微服務呼叫和應用內呼叫有很大的區別,我們不能在進行服務間呼叫時無感知,需要知道它面臨的問題
- 對外部有了依賴,外部是不可靠的
- 有了網路呼叫
解法可以精煉為4條
- 根據業務需要,判斷依賴型別,做好對應的降級
- 設定合理的超時時間
- 呼叫方需要對不同的服務呼叫設定連線池隔離
- 呼叫方需要有熔斷機制
這些問題看似都很簡單,但是根據我的觀察,真的有很多人寫了無數的rpc呼叫,還沒有意識到這些問題。
微服務架構