摘要
目前大部分的系統(tǒng)架構(gòu)都是微服務架構(gòu)衩椒,就算沒有注冊中心蚌父、服務管理,也肯定是多個服務毛萌,單體服務比較少了苟弛。 大家平時需要在應用內(nèi)調(diào)用rpc接口也比較多,那么有沒有思考過——微服務之間的調(diào)用和應用內(nèi)直接調(diào)用有什么區(qū)別呢阁将?面試時是不是經(jīng)常被被問到微服務呢膏秫,本篇文章針對微服務間的方法調(diào)用和應用內(nèi)方法調(diào)用的有啥區(qū)別這個很小的點,談談我的經(jīng)驗做盅。
微服務調(diào)用特點
先從單體應用說起
單體應用 單體引用通過一個服務節(jié)點直接組裝好數(shù)據(jù)缤削,返回給調(diào)用者。所有的方法調(diào)用都發(fā)生在應用內(nèi)部吹榴。
微服務應用
商品詳情服務需要調(diào)用商品亭敢,營銷等多個服務組裝好商品詳情頁的數(shù)據(jù)
微服務調(diào)用和應用內(nèi)調(diào)用不同點在于它是跨進程的,甚至是跨節(jié)點的图筹,這意味著什么呢
使用k8s編排微服務時帅刀,我們可以讓不同的服務放在同一個節(jié)點的不同docker container上让腹,但是考慮到網(wǎng)絡不可靠,和容災扣溺, 服務之間不可避免會放到不同的節(jié)點/機架上骇窍,所以下文都以跨節(jié)點來討論
意味著兩點
· 對外部有了依賴
· 如果是跨節(jié)點,就有了網(wǎng)絡調(diào)用锥余。我們知道網(wǎng)絡都是不可靠的
關(guān)于網(wǎng)絡有幾個著名的錯誤推論:
The network is reliable(網(wǎng)絡是可靠的) 錯
Latency is zero.(延遲可以為0) 錯
Bandwidth is infinite(帶寬是無限的) 錯
The network is secure(網(wǎng)絡是安全的) 錯
Topology doesn't change(網(wǎng)絡拓撲結(jié)構(gòu)不會變) 錯
Transport cost is zero(網(wǎng)絡傳輸耗時為0) 錯
The network is homogeneous(網(wǎng)絡是同類的) 錯
我們需要做什么
存在上述兩個問題后腹纳,那么我們需要在寫微服務間方法調(diào)用時注意什么的
對外部有了依賴 微服務架構(gòu)設計中有一條重要的原則叫嚴出寬進,嚴出意思就是說你提供給其他服務的東西要盡可能的進行嚴格的校驗驱犹。寬進就是你調(diào)用別人的接口要寬容嘲恍,兼容各種情況。比如說你需要考慮別人的節(jié)點down了/api超時/api不可用等等因素着绷。
為了解決這個問題蛔钙,我們必須要針對具體業(yè)務,分析依賴類型荠医,是強依賴還是弱依賴,強依賴包裝成自己的服務異常返回碼/或者直接告訴前端調(diào)用不可用桑涎。弱依賴彬向,catch所有異常,無論依賴方發(fā)生什么攻冷,不能影響我的接口返回娃胆。
此外,我依賴的服務某段時間內(nèi)接口錯誤率很高等曼,調(diào)用方還在不停的發(fā)送請求里烦,那么就會一直得到錯誤的結(jié)果,這時候這些請求其實是無效的禁谦,所以這時候需要客戶端熔斷胁黑,不再去調(diào)用服務方,給服務方恢復的時間州泊,等過段時間再去重試丧蘸,發(fā)現(xiàn)服務方可用時,再去調(diào)用遥皂。
網(wǎng)絡調(diào)用
網(wǎng)絡調(diào)用是耗時的力喷,所以我們需要利用池化技術(shù),復用連接演训,比如在單體應用中我們需要與數(shù)據(jù)庫連接弟孟,會利用到數(shù)據(jù)庫連接池來提高數(shù)據(jù)操作效率。那么微服務調(diào)用也是這么個道理样悟,我們與其他服務建議http/tcp連接拂募,也需要建立連接池。另外一個服務可能會依賴多個微服務,不能因為和某個服務之間的連接出了問題没讲,影響到與其他服務的連接眯娱,所以需要做連接池隔離。
服務間調(diào)用有可能失敗爬凑,所以我們需要有重試機制徙缴,比如因為網(wǎng)絡抖動引發(fā)的超時問題,我們可以通過重試提高API的可用性嘁信。 但是思考一下壞的情況于样,某段時間網(wǎng)絡或者服務端真的有問題了∨司福客戶端超時時間設置的很大的話穿剖,客戶端等待的時間就會很長,然后再加上重試機制卦溢,就會將客戶端的連接占滿糊余,造成客戶端相關(guān)API不可用。
幾個案例
分享幾個微服務調(diào)用的故障案例单寂,幫助大家進行場景化思考 為啥要分享這些案例呢贬芥,因為TMD的這些案例都是血的教訓,造成線上故障宣决,不是我的錯蘸劈,卻要我背鍋
案例1:
新上線了一個產(chǎn)品功能,需要推廣尊沸,放在另外一個流量比較大的產(chǎn)品模塊中威沫,展示一些我們產(chǎn)品功能的數(shù)據(jù)。
出于某種原因洼专,我們的服務mock了rpc調(diào)用數(shù)據(jù)棒掠,返回null。結(jié)果其他服務整個前臺頁面掛了壶熏,掛了句柠,掛了。
典型的強弱依賴問題棒假,調(diào)用方?jīng)]有處理好依賴類型溯职,明明是一個弱依賴沒有處理,變成了強依賴帽哑,造成功能掛了
案例2:
依賴的某個服務需要根據(jù)主鍵List<id>來批量查詢威彰,依賴服務內(nèi)部做分庫分表拆分蚜锨,升級了sdk 在提供的sdk client中做分表路由,將批量id拆分成N個rpc調(diào)用芙沥。這么做的原因是防止批量查詢把數(shù)據(jù)庫連接池打爆找颓。 [圖片
忽略了網(wǎng)絡調(diào)用
案例3 別人調(diào)我們的服務的某個接口,這個接口RT(耗時時間)P95 < 30ms。但是客戶端調(diào)用的超時時間設置成了500ms,在某次不知道是什么原因的情況下蝌数,調(diào)用方的連接大量block,造成線程阻塞度秘,相關(guān)API不可用顶伞。看服務方監(jiān)控,該接口返回時間正常剑梳,服務方?jīng)]有任何異常唆貌。
沒有正確的設置超時時間
總結(jié)
微服務調(diào)用和應用內(nèi)調(diào)用有很大的區(qū)別,我們不能在進行服務間調(diào)用時無感知垢乙,需要知道它面臨的問題
· 對外部有了依賴锨咙,外部是不可靠的
· 有了網(wǎng)絡調(diào)用
解法可以精煉為4條
· 根據(jù)業(yè)務需要,判斷依賴類型追逮,做好對應的降級
· 設置合理的超時時間
· 調(diào)用方需要對不同的服務調(diào)用設置連接池隔離
· 調(diào)用方需要有熔斷機制