overview
kubernetes的設計裡面大致上分為3部分:
- API驅動型的特點 (
API-driven
) - 控制迴圈(
control loops
)與 條件觸發 (Level Trigger
) - API的可延伸性
而正因為這些設計特性,才使得kubernetes工作非常穩定。
什麼是Level Trigger與 Edge trigger
看到網上有資料是這麼解釋兩個屬於的:
-
條件觸發(level-trigger,也被稱為水平觸發)LT指: 只要滿足條件,就觸發一個事件(只要有資料沒有被獲取,就不斷通知)。
-
邊緣觸發(edge-trigger)ET: 每當狀態變化時,觸發一個事件。
通過查詢了一些資料,實際上也不明白這些究竟屬於哪門科學中的理論,但是具體解釋起來看的很明白。
LEVEL TRIGGERING:當電流有兩個級別,VH
和 VL
。代表了兩個觸發事件的級別。如果將VH
設定為LED在正時鐘。當電壓為VH時,LED可以在該時間線任何時刻點亮。這稱為LEVEL TRIGGERING,每當遇到VH
時間線就會觸發事件。事件是在時間內的任何時刻開始,直到滿足條件。
Edge TRIGGERING:
如圖所示,會看到上升線與下降線,當事件在上升/下降邊緣觸發時(兩個狀態的交點),稱為邊緣觸發(Edge TRIGGERING:)。
如果需要開啟LED燈,則當時鍾從VL
轉換到VH
時才會亮起,而不是一家處在對應的時鐘線上,僅僅是在過渡時亮起。
為什麼kubernetes使用Level Trigger而不使用Edge trigger
如圖所述,兩種不同的設計模式,隨著時間形狀進行相應,當系統在由高轉低,或由低轉高時,系統處在關閉或者不可控的異常狀態下,應如何觸發對應的事件呢。
換一種方式來來解釋,比如說通過 加法運算,如下,i=3,當給I+4作為一個操作觸發事件。
# let i=3
# let i+=4
# let i
# echo $i
7
當為Edge trigger
時操作的情況下,將看到 i+4
,而在 level trigger
時看到的是 i=7
。這裡將會從``i+4` 一直到下一個訊號的觸發。
訊號的干擾
通常情況下,兩者是沒有區別的,但在大規模分散式網路環境中,有很多因素的影響下,任何都是不可靠的,在這種情況下會改變了我們對事件訊號的感知。
如圖所示,圖為Level Trigger
與Edge trigger
的訊號發生模擬,在理想情況下,兩者間並沒有什麼不同。
一次中斷場景
由圖可知,Edge trigger
當在恰當的時間點發生訊號中斷,會對整個流產生很大的影響,甚至改變了整個狀態,對於較少的干擾並不會對有更好的結果,而單次的中斷,使Edge trigger
錯過了從高到低的變化,而 level trigger
基本上保證了整個訊號量的所有改變狀態。
兩次中斷的場景下
由圖可看到,訊號的上升和下降中如果存在了中斷,Edge trigger
丟失了上升的訊號,但最終狀態是正確的。
在訊號狀態的兩次變化時發生了兩次中斷,Level Trigger
與Edge trigger
之間的區別很明顯,Edge trigger
的訊號錯過了第一次上升,而Level Trigger
保持了最後觀察到的狀態,知道拿到了其他狀態,這種模式保證了得到的訊號基本的正確性,但是發生延遲到中斷恢復後。
通過運算來表示兩種模式的變化情況
完整的訊號
# let i=2
# let i+1
# let i-=1
# let i+1
# echo $i
3
Edge trigger
# let i=2
# let i+1
(# let i-=1) miss this
# let i+1
# echo $i
4
如何使理想狀態和實際狀態一樣呢?
在Kubernetes中,不僅僅是觀察物件的一個訊號,還觀察了其他兩個訊號,叢集的期待狀態與實際狀態,期望的狀態是使用者期望叢集所處的狀態,如我執行了2個例項(pod)。在最理想的場景下,叢集的實際狀態與期待狀態是相同的,但這個過程會受到任意的外界因素干擾被影響下,實際狀態與理想狀態發生偏差。
Kubernetes必須接受實際狀態,並將其與所需狀態調和。不斷地這樣做,採取兩種狀態,確定其之間的差異,並糾正其不斷的更改,以使實際狀態達到理想狀態。
如圖所示,在一個Edge trigger
中,最終的結果很可能會與理想中的結果發生偏差。
當初始例項為1時,並希望擴充套件為5個副本,然後再向下縮容到2個副本,則Edge trigger
環境下將看到以下狀態:系統的實際狀態不能立即對這些命令作出反應。正如圖所述,當只有3個副本在執行時,它可能會終止3個副本。這就給我們留下了0個副本,而不是所需的2個副本。
# let replicas=1
# let replicas += 4 # 此時副本數為5,但是這個過程需要時間而不是立即完成至理想狀態
# let replicas -= 3 # 當未完成時又接到訊號的變化,此時副本數為3,減去3,很可能實際狀態為0,與理想狀態2發生了偏差
而使用Level Trigger
時,會總是比較完整的期望狀態和實際狀態,直到實際狀態與期望狀態相同。這大大減少了狀態同步間(錯誤)的產生。
summary
每一種觸發器的產生一定有其道理,Edge trigger
本身並不是很差,只是應用場景的不同,而使用的模式也不同,比如nginx的高效能就是使用了Edge trigger
模型,如nginx使用了 Level trigger
在大併發下,當發生了變更訊號等待返回時,發生大量客戶端連線在偵聽佇列,而Edge trigger
模型則不會出現這種情況。
綜上所述,kubernetes在設計時,各個元件需要感知資料的最終理想狀態,無需擔心錯過資料變化的過程。而設計kubernentes系統訊息通知機制(或資料實時通知機制),也應滿足以下要求:
-
實時性(即資料變化時,相關元件感覺越快越好)。訊息必須是實時的。在
list/watch
機制下,每當apiserver資源有狀態變化事件時,都會及時將事件推送到客戶端,以保證訊息的實時性。 -
訊息序列:訊息的順序也很重要。在併發場景下,客戶端可能會在短時間內收到同一資源的多個事件。對於關注最終一致性的kubernetes來說,它需要知道哪個是最新的事件,並保證資源的最終狀態與最新事件所表達的一致。kubernetes在每個資源事件中都攜帶一個
resourceVersion
標籤,這個標籤是遞增的。因此,客戶端在併發處理同一資源的事件時,可以比較resourceVersion
,以確保最終狀態與最新事件的預期狀態一致。 -
訊息的可靠性,保證訊息不丟失或者有可靠的重新獲取的機制(比如
kubelet
和kube-apisever
之間的網路波動(network flashover
)需要保證kubelet在網路恢復後可以接收到網路故障時產生的訊息)。
正是因為Kubernetes使用了 Level trigger
才讓叢集更加可靠。
Reference