client-go源碼分析(2.2):DeltaFIFO

前言

本文聚焦client-go v11.0.0 controller框架DeltaFIFO對象,分析源碼理解DeltaFIFO的實現(xiàn)。DeltaFIFO是client-go controller framework的重要環(huán)節(jié),它的作用是保證Reflector和Indexer之間對象同步??梢哉f,DeltaFIFO是連接生產者(Reflector)和消費者(Indexer)的通道。閱讀本文前希望讀者已閱讀《client-go源碼分析》前面的系列文章,要求已了解Informer和Reflector。

1 DeltaFIFO介紹

DeltaFIFO構造函數(shù)

以簡單的示意圖描述DeltaFIFO的結構:

DeltaFIFO核心結構示意圖

DeltaFIFO的核心結構包括items和queue,對應Delta和FIFO。

1.1 Delta

Delta顧名思義是變化和差異,因此items的作用是緩存某個對象的一系列變更行為(Deltas)。正因為這里保存的是Delta(當前對象和前一個對象的差異),有序地保存一系列行為才有意義,單獨的某個Updated狀態(tài)無法正確同步對象。

items是map結構,key是由keyfunc計算出來的對象key;value是deltas,即delta列表。delta數(shù)據(jù)結構如下:

Delta數(shù)據(jù)結構

當前版本DeltaType的值只有Added, Updated, Deleted, Sync;Object即runtime.Object。

1.2 FIFO

FIFO即先進先出隊列,這里queue僅把對象鍵(objkey)入列。消費者通過objkey查找items的Deltas并依次同步所有行為。queue是對象同步處理隊列,消費者僅處理queue中存在的objkey。

2 DeltaFIFO基本功能

上述已經提到DeltaType只有四種:Added, Updated, Deleted, Sync。這里僅分析最難理解的Sync函數(shù),Sync是List機制和Resync觸發(fā)的全量同步;Added,Updated,Deleted是Watch觸發(fā)的增量同步。

2.1 深入理解Sync:Replace()

Sync是比較特殊的處理,理解了Sync也就不難理解其他行為。Sync是指Reflector全量同步Indexer,從DelaFIFO的實現(xiàn)看是調用Replace函數(shù)“重建”Indexer。DelaFIFO的Replace實現(xiàn)了Sync行為(Resync也調用該函數(shù))。controller第一次啟動時,Reflector的List機制觸發(fā)DeltaFIFO的Sync行為,《Client-Go源碼分析(2.1):Reflector》會提到r.syncWith(items,

resourceVersion)函數(shù),該函數(shù)調用

func (f *DeltaFIFO) Replace(list []interface{},

resourceVersion string) error

開始分析Replace代碼前,先看一個重要的公共函數(shù)queueActionLocked,DeltaFIFO的所有行為都會調用它。queueActionLocked的功能是:僅處理某個動作。若處理一系列動作或多個對象,需要外部調用者重復調用它。

queueActionLocked注釋
Replace注釋1
Replace注釋2
Replace注釋3

2.2 queueActionLocked的特殊處理分析

上文提到的queueActionLocked特殊處理針對一種場景:

obj的id是objkey1,該對象最后一次動作是Deleted,并且objkey1仍在queue中等待處理。此時周期性被動觸發(fā)一次Resync(會調用Replace)。k8s集群真實的runtime.Object已刪除,但Indexer的同步尚未完成,Indexer緩存里仍有這個對象。

sync場景分析

假設queueActionLocked更新了deltas如上圖(左)所示,該對象會先刪除,然后添加回來!從Pop()函數(shù)里的回調函數(shù)Process可以看到這個過程。前幾篇文章已經提到過,Process的入?yún)bj是Deltas隊列,該函數(shù)依次處理每個Delta行為。當Process處理到上圖(左)Deleted時Index會刪除對象;當它處理到最后的Sync時,Index又會添加這個對象。因此,queueActionLocked通過特殊處理規(guī)避了這個問題,現(xiàn)有代碼的處理方式如上圖(右)所示,直接返回不更新deltas。

Process的實現(xiàn)

2.3 sync場景的DeleteFinalStateUnknown分析

// DeletedFinalStateUnknown isplaced into a DeltaFIFO in the case where

// an object was deleted but thewatch deletion event was missed. In this

// case we don't know the final"resting" state of the object, so there's

// a chance the included `Obj` isstale.

這個對象困惑了我許久,從注釋上看是針對Watch Deleted事件丟失,導致k8s實際對象和Indexer緩存不一致的場景。我們用圖展示兩種場景:1. Deleted事件未丟失,只是queue待處理該對象;2. Deleted事件丟失。

Deleted消息是否丟失場景比較

上圖(左)是Deleted消息丟失的代碼處理,queueActionLocked會添加DeleteFinalStateUnknown對象到deltas,并保存到Indexer。DeleteFinalStateUnknown是對runtime.Object的封裝。

上圖(右)是Deleted消息未丟失的代碼處理。deltas對象變化過程如下:

deltas對象變化過程

從Process回調函數(shù)看,是直接調用clientState.Delete(d.Object)刪除對象的,Indexer計算對象鍵是否會異常呢?抱著好奇心看了一眼keyFunc(計算對象鍵的函數(shù),下一篇文章會講到)DeletionHandlingMetaNamespaceKeyFunc:

DeletionHandlingMetaNamespaceKeyFunc的實現(xiàn)

DeletionHandlingMetaNamespaceKeyFunc果然有對DeletedFinalStateUnknown的處理(obj.(DeletedFinalStateUnknown)是類型斷言用法),因此不需要擔心獲取對象鍵會異常。如果是我們自己實現(xiàn)keyFunc,一樣要考慮到DeletedFinalStateUnknown這個而特殊對象。

到此為止DeltaFIFO的主要機制已分析完畢。

3 結語

DeltaFIFO的部分代碼比較晦澀,尤其是特殊處理增加了閱讀難度。特殊處理一時爽,代碼維護兩行淚。

4 參考文檔

https://blog.csdn.net/li_101357/article/details/89763992

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容