因為有了集群,每次傳送請求前,rpc 框架會根據路由和負載均衡演算法選擇乙個具體的 ip 位址。為了保證請求成功,就需要確保每次選擇出來的 ip 對應的連線是健康的。
但是呼叫方各個服務集群節點之間的網路狀態是瞬息萬變的,兩者之間可能會出現閃斷或者網路裝置損壞等情況,那麼怎麼保證連線一定是可用的呢?
終極的解決方案是讓呼叫方實時感知到節點的狀態變化,這樣他們才能做出正確的選擇。那麼在 roc 框架裡面,怎麼設計這台機制呢?
當服務方下線,正常情況下我們會收到連線斷開的通知事件,在這個事件裡面直接加處理邏輯不就可以了?但是不行,因為應用健康狀態不僅包括 tcp 連線狀態,還包括應用本身是否存活,很多情況下 tcp 連線沒有斷開,但是應用可能已經僵死了。
所以,業內常用的檢測方式就是用心跳檢測機制。心跳機制說起來也不複雜,其實就是服務呼叫方每隔一段時間就問一下服務提供方,「兄弟,你還好吧」,然後服務方很誠實地告訴呼叫方它目前的狀態。
一般,服務方會有三種情況:
節點的狀態並不是固定不變的,他會根據心跳或重連的結果來動態變化,具體狀態間轉換圖如下:
首先,一開始初始化的時候,如果連線建立成功,那就是健康狀態,否則就是死亡狀態。這裡沒有亞健康這樣的中間態。如果健康狀態的節點連續出現幾次不能響應心跳請求的情況,那麼就會被標記為亞健康狀態,也就是說,服務呼叫方會覺得它「生病了」。
處於亞健康狀態,如果連續幾次都能正常響應心跳請求,那就可以轉回健康狀態,證明病好了。如果病一直好不了,那麼就會被斷定是死亡節點,死亡之後還需要善後,比如關閉連線。
當然,死亡並不是正真死亡,他還有復活機會。如果某個時間點裡,死亡的節點能夠重連成功,那它就可以重新被標記為健康狀態。
當服務方通過心跳機制理解了節點的狀態之後,每次傳送請求的時候,就可以優先從健康列表裡面選擇乙個節點,當然,如果健康列表為空,為了提高可用性,可以嘗試從亞健康列表裡面選擇乙個,這就是具體的策略了。
乙個節點從健康狀態過渡到亞健康狀態的前提是「連續」心跳失敗次數必須達到某乙個閾值,比如3次,看你具體的配置。
而在我們的場景裡,節點的心跳日誌只是間歇性失敗,也就是時好時壞,這樣,失敗次數根本沒到閾值,呼叫方只是會覺得它「生病」了,並且很快就好了,那怎麼解決呢?
你可能會想,那調低閾值唄,這樣雖然可以解決,但是治標不治本,會導致呼叫方很快接觸連續心跳失敗而造成斷開連線。
問題的核心是服務節點網路有問題,心跳間歇性失敗,我們現在判斷節點狀態只有乙個維度,那就是心跳檢測,那是不是可以再加上業務請求的維度呢?
但是這樣就沒有問題了嗎?
我們可以使用可用率,可用率的計算方式是某乙個時間視窗內介面的呼叫成功次數的百分比(成功次數/總呼叫次數)。這樣既考慮了高低頻的呼叫介面,也兼顧了介面響應時間不同的問題。
為啥記憶體需要堆?
翻譯自 我們需要知道的最重要的事情是棧的功能和堆的功能這兩者是有顯著區別的。在乙個典型的程式語言中,在乙個方法呼叫的時候,乙個 棧幀 就會被建立出來。隨後,所有的該方法的本地變數就會在這個棧幀的範圍中被建立。然後,當這個方法返回的時候,該方法的棧幀就被 刪除 了。這些都是 自動 的。高層開發人員不需...
重寫equals為啥需要重寫hashCode
以前一直記得重寫equals要把hashcode也要重寫了,但是一直也是沒有搞明白,最近在看一些東西,覺得有必要記錄一下。equals是object類的方法,這個方法的作用是比較兩個物件是否相等的,可能有人會問了,使用 號不就可以比較了,為啥非得使用equals方法呢。假設你有乙個student類,...
docker在windows上為啥需要虛擬化。
docker在linux上執行不需要虛擬化,但是,如果在windows上安裝執行就需要虛擬化,找到答案了。docker 底層的核心技術包括 linux 上的名字空間 namespaces 控制組 control groups union 文 件系統 union file systems 和容器格式 ...