服務探活的五種方式

2022-09-14 04:48:10 字數 3220 閱讀 1864

幾個月前,我在《4個實驗,徹底搞懂tcp連線的斷開》這篇文章中給自己挖了個坑:

文中提到的實際問題就是服務探活,今天來填上這個坑。

在微服務架構下,服務提供方(provider)的節點一般不止乙個,消費方(consumer)根據負載均衡演算法挑選乙個健康的節點進行呼叫。識別provider節點是否健康,這便是服務探活要討論的內容。

健康的節點可定義為能正常響應consumer請求的節點,不健康自然是不能正常響應consumer請求的節點

不健康的原因可能是物理上的斷電、斷網、硬體故障,也可能是網路延遲、程序異常退出或程序無法處理請求。

總之一句話總結起來就是provider節點沒有摘除流量前,就無法處理請求了。可以分為三類:

乙個provider節點的狀態只有健康和不健康,由健康到不健康稱之為探死,由不健康到健康稱之為探活,一般我們不分這麼細,統一叫探活

至於是誰來探,可能是consumer,也可能是註冊中心,甚至是某個單獨的探活元件。我們就從探活的發起者來列舉目前主流的探活方式。

最簡單的是在consumer側進行探活,如果consumer呼叫provider報錯,則consumer將該provider剔掉,為了防止偶發的網路抖動或其他干擾,可設定乙個時間視窗,視窗內失敗達n 次則剔除,當過了這段時間,再把這個provider重置為正常。

這種方式的典型代表是nginx,nginx可配置多長時間內,失敗多少次則認為該provider不可用,其失敗可以是連線失敗、也可以是某些http狀態碼(如4xx,5xx)

這種方案的缺點很明顯,需要真實流量去檢測,如果配置了失敗繼續**給下乙個provider,則時間視窗的開始的一段時間內耗時上公升,未配置則直接報錯,所以無論怎麼配置,對服務都是有影響的。

consumer被動健康檢查的主要問題在於使用了真實流量檢測,其實只要稍微改一改,使用旁路的方式去檢測即可避免。

阿里的tengine開源了乙個nginx_upstream_check_module模組來做主動健康檢查。

這個旁路可以一直去探測provider,當檢測到異常時,將其標記為不可用狀態,請求不再發往該provider,若檢測到provider 健康時,再將其標記為健康。

consumer側的探活在rpc框架實現的比較少,不知道是基於怎樣的一種考慮,其實有些企業內會在consumer側已經加入了探活機制,比如愛奇藝在dubbo的consumer側增加了探活機制,其實我所在的公司內部rpc框架也是有consumer側的服務探活。

參考《愛奇藝在 dubbo 生態下的微服務架構實踐》

但dubbo官方沒有整合,至於為什麼,我也去github上問過,不過沒人回覆~

當有乙個註冊中心時,探活這項任務就可以交給註冊中心了。

最簡單的,我們想到了心跳保持這個策略,provider註冊成功後,一直向註冊中心傳送心跳包,註冊中心定時檢查provider,如果長時間未傳送心跳包,就將其置為不可用,並告知consumer,如果心跳恢復,則將其恢復並通知。

某些元件也支援這種續約的特性,如etcd、redis等都可以構建類似的系統。

這種方式的代表是nacos 1.x 版本中的臨時例項

慢慢你會發現這種方式摘除故障節點的時效性和資源的使用成正相關,如果你想要更好的時效性,就必須縮短心跳間隔,從而會增加心跳請求量,每次心跳得更新每個節點的上次心跳時間,占用了大量資源。

為了解決心跳請求占用大量資源的問題,我們想到了tcp 連線不是乙個天然的健康檢查機制嗎?如果僅僅依靠tcp連線可以嗎?

這就是之前文章埋下的坑,再次總結一下這篇文章《4個實驗,徹底搞懂tcp連線的斷開》中關於tcp連線斷開的場景:

2小時肯定不能接受,為了防止這種情況,光靠tcp是不夠的,還得在應用層實現乙個心跳檢測,為了節省資源,可以將心跳包設計的很小,傳送頻率不需要那麼高,通常1分鐘內能感知即可。

因為只有斷電、斷網或硬體故障才會導致無法感知連線的斷開,這個比例很小。

可以參考下圖,雖然圖中的資料是我杜撰的,但**不離十吧,可以看到系統異常只佔1%,這1%中未發資料可能更少,所以可以認為這個概率很小。

這種方式比較常見,像dubbo使用的zookeeper,nacos 2.x版本(grpc)的臨時例項,sofaregistry等等都用了這這種方式。

其中sofaregistry比較有意思,它提出了一種連線敏感的長連線,乍一看以為用了什麼黑科技,後來看了**發現就是tcp連線加應用層的心跳檢測,這些被他們封裝在sofabolt通訊框架中。

參考《海量資料下的註冊中心 - sofaregistry 架構介紹》

但這個方式也有乙個明顯的缺點,如果網路狀況不好的情況下,tcp連線比較容易斷開,會導致節點頻繁上下線。

除了上述的方式,還有一種註冊中心(甚至是乙個單獨的元件)主動探測provider的方式,與consumer主動探測類似,只不過把探測任務移交給了註冊中心或乙個單獨的元件。

主動探測有個最大的優勢是可以擴充套件非常豐富的探測方式,比如最常見的探測埠是否存活,又或者探測provider的乙個http介面返回是否符合預期,甚至可以擴充套件為mysql、redis等等協議的探測。

這也是種能解決服務假死的探活方式,nacos中的永久例項探活就是採用的這種方式。

但這種方式在實際使用的時候要考慮主動探測元件的高可用,高可用就得存在副本,可採取主備方式。

如果單機存在效能瓶頸,還得分布式探活,主備可能就不適合,得有乙個分布式協調者,這要說又得長篇大論。但這裡你知道有這麼個事兒就可以了。

考量探活的指標有三個:

功能上最強的是帶語義的主動探測,時效性最強的要屬長連線會話保持。

穩定性不好說誰強誰弱,但一般會給乙個集群設定乙個探活摘除的比例,比如最多摘除50%機器,防止探活錯誤導致節點全部下線,這也算是一種兜底策略吧。

Soul閘道器中的Http服務探活

服務探活機制是為了發現系統中上下游服務的的狀態。當有新的服務註冊時要通知其他系統,當有服務下線時也要告知其他系統。soul閘道器中有對http服務處理的探活,所有的服務物件儲存在soul admin的upstream map中,這裡面的服務物件有兩個 乙個來自於原有的資料庫,乙個來自於其他服務的註冊...

程序的五種通訊方式

一 管道 1 什麼是管道 我們把乙個程序連線到另乙個程序的資料流稱為乙個管道。它是最古老的程序通訊形式。2 原型 匿名管道 include 功能 建立 名管道 原型int pipe int fd 2 引數fd 件描述符陣列,其中fd 0 表 讀端,fd 1 表 寫端 返回值 成功返回0,失敗返回錯誤...

執行緒的五種建立方式

執行緒的五種建立方式 1 繼承thread類,重寫run 方法,呼叫start 方法啟動執行緒public class testthread1 extends thread public static void main string args 2 實現runnable介面,重寫run 方法,建立r...