Informer 機(jī)制

背景

什么是 Informer 機(jī)制

一個(gè)控制器每次需要獲取對(duì)象的時(shí)候都要訪問(wèn) APIServer置森,這會(huì)給系統(tǒng)帶來(lái)很高的負(fù)載,Informers 的內(nèi)存緩存就是來(lái)解決這個(gè)問(wèn)題的塞琼,此外 Informers 還可以幾乎實(shí)時(shí)的監(jiān)控對(duì)象的變化,而不需要輪詢請(qǐng)求禁舷,這樣就可以保證客戶端的緩存數(shù)據(jù)和服務(wù)端的數(shù)據(jù)一致彪杉,就可以大大降低 APIServer 的壓力了。


image.png

如上圖展示了 Informer 的基本處理流程:

以 events 事件的方式從 APIServer 獲取數(shù)據(jù)

提供一個(gè)類似客戶端的 Lister 接口牵咙,從內(nèi)存緩存中 get 和 list 對(duì)象

為添加派近、刪除、更新注冊(cè)事件處理程序

此外 Informers 也有錯(cuò)誤處理方式洁桌,當(dāng)長(zhǎng)期運(yùn)行的 watch 連接中斷時(shí)渴丸,它們會(huì)嘗試使用另一個(gè) watch 請(qǐng)求來(lái)恢復(fù)連接,在不丟失任何事件的情況下恢復(fù)事件流。如果中斷的時(shí)間較長(zhǎng)谱轨,而且 APIServer 丟失了事件(etcd 在新的 watch 請(qǐng)求成功之前從數(shù)據(jù)庫(kù)中清除了這些事件)戒幔,那么 Informers 就會(huì)重新 List 全量數(shù)據(jù)。

而且在重新 List 全量操作的時(shí)候還可以配置一個(gè)重新同步的周期參數(shù)土童,用于協(xié)調(diào)內(nèi)存緩存數(shù)據(jù)和業(yè)務(wù)邏輯的數(shù)據(jù)一致性诗茎,每次過(guò)了該周期后,注冊(cè)的事件處理程序就將被所有的對(duì)象調(diào)用献汗,通常這個(gè)周期參數(shù)以分為單位敢订,比如10分鐘或者30分鐘。

Informers 的這些高級(jí)特性以及超強(qiáng)的魯棒性罢吃,都足以讓我們不去直接使用客戶端的 Watch() 方法來(lái)處理自己的業(yè)務(wù)邏輯楚午,而且在 Kubernetes 中也有很多地方都有使用到 Informers。但是在使用 Informers 的時(shí)候尿招,通常每個(gè) GroupVersionResource(GVR)只實(shí)例化一個(gè) Informers醒叁,但是有時(shí)候我們?cè)谝粋€(gè)應(yīng)用中往往有使用多種資源對(duì)象的需求,這個(gè)時(shí)候?yàn)榱朔奖愎蚕?Informers泊业,我們可以通過(guò)使用共享 Informer 工廠來(lái)實(shí)例化一個(gè) Informer把沼。

共享 Informer 工廠允許我們?cè)趹?yīng)用中為同一個(gè)資源共享 Informer,也就是說(shuō)不同的控制器循環(huán)可以使用相同的 watch 連接到后臺(tái)的 APIServer吁伺,例如饮睬,kube-controller-manager 中的控制器數(shù)據(jù)量就非常多,但是對(duì)于每個(gè)資源(比如 Pod)篮奄,在這個(gè)進(jìn)程中只有一個(gè) Informer捆愁。

Informer 是 client-go 中的核心工具包,已經(jīng)被 kubernetes 中眾多組件所使用窟却。所謂 Informer昼丑,其實(shí)就是一個(gè)帶有本地緩存和索引機(jī)制的、可以注冊(cè) EventHandler 的 client夸赫,本地緩存被稱為 Store菩帝,索引被稱為 Index。使用 informer 的目的是為了減輕 apiserver 數(shù)據(jù)交互的壓力而抽象出來(lái)的一個(gè) cache 層, 客戶端對(duì) apiserver 數(shù)據(jù)的 "讀取" 和 "監(jiān)聽" 操作都通過(guò)本地 informer 進(jìn)行茬腿。

Informer 的主要功能:

  • 同步數(shù)據(jù)到本地緩存

  • 根據(jù)對(duì)應(yīng)的事件類型呼奢,觸發(fā)事先注冊(cè)好的 ResourceEventHandle

為什么需要 Informer 機(jī)制?

我們知道Kubernetes各個(gè)組件都是通過(guò)REST API跟API Server交互通信的切平,而如果每次每一個(gè)組件都直接跟API Server交互去讀取/寫入到后端的etcd的話握础,會(huì)對(duì)API Server以及etcd造成非常大的負(fù)擔(dān)。 而Informer機(jī)制是為了保證各個(gè)組件之間通信的實(shí)時(shí)性悴品、可靠性禀综,并且減緩對(duì)API Server和etcd的負(fù)擔(dān)简烘。

Informer 需要滿足哪些要求?

  • 消息可靠性

  • 消息實(shí)時(shí)性

  • 消息順序性

  • 高性能

核心功能

image.png

Informer的工作流程

  • Informer 首先會(huì) list/watch apiserver定枷,Informer 所使用的 Reflector 包負(fù)責(zé)與 apiserver 建立連接孤澎,Reflector 使用 ListAndWatch 的方法,會(huì)先從 apiserver 中 list 該資源的所有實(shí)例依鸥,list 會(huì)拿到該對(duì)象最新的 resourceVersion,然后使用 watch 方法監(jiān)聽該 resourceVersion 之后的所有變化悼沈,若中途出現(xiàn)異常贱迟,reflector 則會(huì)從斷開的 resourceVersion 處重現(xiàn)嘗試監(jiān)聽所有變化,一旦該對(duì)象的實(shí)例有創(chuàng)建絮供、刪除衣吠、更新動(dòng)作,Reflector 都會(huì)收到"事件通知"壤靶,這時(shí)缚俏,該事件及它對(duì)應(yīng)的 API 對(duì)象這個(gè)組合,被稱為增量(Delta)贮乳,它會(huì)被放進(jìn) DeltaFIFO 中忧换。

  • Informer 會(huì)不斷地從這個(gè) DeltaFIFO 中讀取增量,每拿出一個(gè)對(duì)象向拆,Informer 就會(huì)判斷這個(gè)增量的時(shí)間類型亚茬,然后創(chuàng)建或更新本地的緩存,也就是 store浓恳。

  • 如果事件類型是 Added(添加對(duì)象)刹缝,那么 Informer 會(huì)通過(guò) Indexer 的庫(kù)把這個(gè)增量里的 API 對(duì)象保存到本地的緩存中,并為它創(chuàng)建索引颈将,若為刪除操作梢夯,則在本地緩存中刪除該對(duì)象。

  • DeltaFIFO 再 pop 這個(gè)事件到 controller 中晴圾,controller 會(huì)調(diào)用事先注冊(cè)的 ResourceEventHandler 回調(diào)函數(shù)進(jìn)行處理颂砸。

  • 在 ResourceEventHandler 回調(diào)函數(shù)中,其實(shí)只是做了一些很簡(jiǎn)單的過(guò)濾死姚,然后將關(guān)心變更的 Object 放到 workqueue 里面沾凄。

  • Controller 從 workqueue 里面取出 Object,啟動(dòng)一個(gè) worker 來(lái)執(zhí)行自己的業(yè)務(wù)邏輯知允,業(yè)務(wù)邏輯通常是計(jì)算目前集群的狀態(tài)和用戶希望達(dá)到的狀態(tài)有多大的區(qū)別撒蟀,然后孜孜不倦地讓 apiserver 將狀態(tài)演化到用戶希望達(dá)到的狀態(tài),比如為 deployment 創(chuàng)建新的 pods温鸽,或者是擴(kuò)容/縮容 deployment保屯。

  • 在worker中就可以使用 lister 來(lái)獲取 resource手负,而不用頻繁的訪問(wèn) apiserver,因?yàn)?apiserver 中 resource 的變更都會(huì)反映到本地的 cache 中姑尺。

List & Watch

image.png

List所做的竟终,就是向API Server發(fā)送一個(gè)http短鏈接請(qǐng)求,羅列所有目標(biāo)資源的對(duì)象切蟋。而Watch所做的是實(shí)際的“監(jiān)聽”工作统捶,通過(guò)http長(zhǎng)鏈接的方式,其與API Server能夠建立一個(gè)持久的監(jiān)聽關(guān)系柄粹,當(dāng)目標(biāo)資源發(fā)生了變化時(shí)喘鸟,API Server會(huì)返回一個(gè)對(duì)應(yīng)的事件,從而完成一次成功的監(jiān)聽驻右,之后的事情便交給后面的handler來(lái)做什黑。

這樣一個(gè)List & Watch機(jī)制,帶來(lái)了如下幾個(gè)優(yōu)勢(shì):

  1. 事件響應(yīng)的實(shí)時(shí)性:通過(guò)Watch的調(diào)用堪夭,當(dāng)API Server中的目標(biāo)資源產(chǎn)生變化時(shí)愕把,能夠及時(shí)的收到事件的返回,從而保證了事件響應(yīng)的實(shí)時(shí)性森爽。而倘若是一個(gè)輪詢的機(jī)制恨豁,其實(shí)時(shí)性將受限于輪詢的時(shí)間間隔。

  2. 事件響應(yīng)的可靠性:倘若僅調(diào)用Watch爬迟,則如果在某個(gè)時(shí)間點(diǎn)連接被斷開圣絮,就可能導(dǎo)致事件被丟失。List的調(diào)用帶來(lái)了查詢資源期望狀態(tài)的能力雕旨,客戶端通過(guò)期望狀態(tài)與實(shí)際狀態(tài)的對(duì)比扮匠,可以糾正狀態(tài)的不一致。二者結(jié)合保證了事件響應(yīng)的可靠性凡涩。

  3. 高性能:倘若僅周期性地調(diào)用List棒搜,輪詢地獲取資源的期望狀態(tài)并在與當(dāng)前狀態(tài)不一致時(shí)執(zhí)行更新,自然也可以do the job活箕。但是高頻的輪詢會(huì)大大增加API Server的負(fù)擔(dān)力麸,低頻的輪詢也會(huì)影響事件響應(yīng)的實(shí)時(shí)性。Watch這一異步消息機(jī)制的結(jié)合育韩,在保證了實(shí)時(shí)性的基礎(chǔ)上也減少了API Server的負(fù)擔(dān)克蚂,保證了高性能。

  4. 事件處理的順序性:我們知道筋讨,每個(gè)資源對(duì)象都有一個(gè)遞增的ResourceVersion埃叭,唯一地標(biāo)識(shí)它當(dāng)前的狀態(tài)是“第幾個(gè)版本”,每當(dāng)這個(gè)資源內(nèi)容發(fā)生變化時(shí)悉罕,對(duì)應(yīng)產(chǎn)生的事件的ResourceVersion也會(huì)相應(yīng)增加赤屋。在并發(fā)場(chǎng)景下立镶,K8s可能獲得同一資源的多個(gè)事件,由于K8s只關(guān)心資源的最終狀態(tài)类早,因此只需要確保執(zhí)行事件的ResourceVersion是最新的媚媒,即可確保事件處理的順序性。

ResourceVersion

Kubernetes 請(qǐng)求并發(fā)控制與數(shù)據(jù)一致性(含ResourceVersion涩僻、Update缭召、Patch簡(jiǎn)析)

Kubernetes-resourceVersion機(jī)制分析

秘訣就是 Chunked transfer encoding(分塊傳輸編碼),它首次出現(xiàn)在HTTP/1.1逆日。正如維基百科所說(shuō):

HTTP 分塊傳輸編碼允許服務(wù)器為動(dòng)態(tài)生成的內(nèi)容維持 HTTP 持久鏈接嵌巷。通常,持久鏈接需要服務(wù)器在開始發(fā)送消息體前發(fā)送Content-Length消息頭字段屏富,但是對(duì)于動(dòng)態(tài)生成的內(nèi)容來(lái)說(shuō)晴竞,在內(nèi)容創(chuàng)建完之前是不可知的蛙卤。使用分塊傳輸編碼狠半,數(shù)據(jù)分解成一系列數(shù)據(jù)塊,并以一個(gè)或多個(gè)塊發(fā)送颤难,這樣服務(wù)器可以發(fā)送數(shù)據(jù)而不需要預(yù)先知道發(fā)送內(nèi)容的總大小神年。

當(dāng)客戶端調(diào)用 watch API 時(shí),apiserver 在response 的 HTTP Header 中設(shè)置 Transfer-Encoding的值為chunked行嗤,表示采用分塊傳輸編碼已日,客戶端收到該信息后,便和服務(wù)端該鏈接栅屏,并等待下一個(gè)數(shù)據(jù)塊飘千,即資源的事件信息。例如:

Informer 能保證通過(guò)list+watch不會(huì)丟失事件栈雳,如果網(wǎng)絡(luò)抖動(dòng)重新恢復(fù)后护奈,watch會(huì)帶著之前的resourceVersion號(hào)重連,resourceVersion是單調(diào)遞增的哥纫, API Server 收到該請(qǐng)求后會(huì)將所有大于該resourceVersion的變更同步過(guò)來(lái)霉旗。

二級(jí)緩存

二級(jí)緩存屬于 Informer 的底層緩存機(jī)制,這兩級(jí)緩存分別是 DeltaFIFO 和 LocalStore蛀骇。這兩級(jí)緩存的用途各不相同厌秒。DeltaFIFO 用來(lái)存儲(chǔ) Watch API 返回的各種事件 ,LocalStore 只會(huì)被 Lister 的 List/Get 方法訪問(wèn) 擅憔。

如果K8s每次想查看資源對(duì)象的狀態(tài)鸵闪,都要經(jīng)歷一遍L(zhǎng)ist調(diào)用,顯然對(duì) API Server 也是一個(gè)不小的負(fù)擔(dān)暑诸,對(duì)此岛马,一個(gè)容易想到的方法是使用一個(gè)cache作保存棉姐,需要獲取資源狀態(tài)時(shí)直接調(diào)cache,當(dāng)事件來(lái)臨時(shí)除了響應(yīng)事件外啦逆,也對(duì)cache進(jìn)行刷新伞矩。

雖然 Informer 和 Kubernetes 之間沒(méi)有 resync 機(jī)制,但 Informer 內(nèi)部的這兩級(jí)緩存之間存在 resync 機(jī)制夏志。

Resync

Resync 機(jī)制會(huì)將 Indexer 的本地緩存重新同步到 DeltaFIFO 隊(duì)列中乃坤。一般我們會(huì)設(shè)置一個(gè)時(shí)間周期,讓 Indexer 周期性地將緩存同步到隊(duì)列中沟蔑。直接 list/watch API Server 就已經(jīng)能拿到集群中資源對(duì)象變化的 event 了湿诊,這里引入 Resync 的作用是什么呢?去掉會(huì)有什么影響呢瘦材?

自定義事件處理

ResourceEventHandler 用于處理對(duì)象的變更事件厅须,用戶可以通過(guò)實(shí)現(xiàn) ResourceEventHandler 接口,并調(diào)用 sharedIndexInformer.AddEventHandler() 或 sharedIndexInformer.AddEventHandlerWithResyncPeriod() 方法注冊(cè)到 sharedProcessor 中食棕。這樣朗和,當(dāng)數(shù)據(jù)發(fā)送變化時(shí),就會(huì)回調(diào) ResourceEventHandler 中對(duì)應(yīng)的 OnAdd/OnUpdate/OnDelete 方法來(lái)實(shí)現(xiàn)用戶自定義的處理邏輯

核心對(duì)象

Informer相關(guān)

client-go 中提供了幾種不同的 Informer:

  • 通過(guò)調(diào)用 NewInformer 函數(shù)創(chuàng)建一個(gè)簡(jiǎn)單的不帶 indexer 的 Informer簿晓。

  • 通過(guò)調(diào)用 NewIndexerInformer 函數(shù)創(chuàng)建一個(gè)簡(jiǎn)單的帶 indexer 的 Informer眶拉。

  • 通過(guò)調(diào)用 NewSharedIndexInformer 函數(shù)創(chuàng)建一個(gè) Shared 的 Informer。

  • 通過(guò)調(diào)用 NewDynamicSharedInformerFactory 函數(shù)創(chuàng)建一個(gè)為 Dynamic 客戶端的 Shared 的 Informer憔儿。

這里帶有 Indexer 和不帶 Indexer 的大家好理解寫忆植,從字面意思來(lái)看,就是一個(gè)是帶有 Indexer 功能一個(gè)不帶有 Indexer 功能的 Informer谒臼。而這里的 Shared 的 Informer 引入朝刊,其實(shí)是因?yàn)殡S著 K8S 中,相同資源的監(jiān)聽者在不斷地增加蜈缤,從而導(dǎo)致很多調(diào)用者通過(guò) Watch API 對(duì) API Server 建立一個(gè)長(zhǎng)連接去監(jiān)聽事件的變化拾氓,這將嚴(yán)重增加了 API Server 的工作負(fù)載,及資源的浪費(fèi)劫樟。

比如在 kube-controller-manager 組件中痪枫,有很多控制管理都需要監(jiān)聽 Pod 資源的變化,如果都獨(dú)立的調(diào)用 Informer 去維護(hù)一個(gè)對(duì) APIServer 的長(zhǎng)連接叠艳,這將導(dǎo)致 kube-controller-manager 中資源的浪費(fèi)及增加了 APIServer 的負(fù)載奶陈,而不同控制管理者通過(guò)創(chuàng)建 Shared 的 Informer 則實(shí)現(xiàn)了這些控制管理者使用同一個(gè) Watch 去和 APIServer 建立長(zhǎng)連接,并在收到事件后附较,分發(fā)給下游的調(diào)用者吃粒。

SharedInformer

我們平時(shí)說(shuō)的 Informer 其實(shí)就是 SharedInformer,它是可以共享使用的拒课。如果同一個(gè)資源的 Informer 被實(shí)例化多次徐勃,那么就會(huì)運(yùn)行多個(gè) ListAndWatch 操作事示,這會(huì)加大 APIServer 的壓力。而 SharedInformer 通過(guò)一個(gè) map 來(lái)讓同一類資源的 Informer 實(shí)現(xiàn)共享一個(gè) Refelctor僻肖,這樣就不會(huì)出現(xiàn)上面這個(gè)問(wèn)題了。

Informer通過(guò)Local Store緩存目標(biāo)資源對(duì)象臀脏,且僅為自己所用劝堪。但是在K8s中,一個(gè)Controller可以關(guān)心不止一種資源揉稚,使得多個(gè)Controller所關(guān)心的資源彼此會(huì)存在交集秒啦。如果幾個(gè)Controller都用自己的Informer來(lái)緩存同一個(gè)目標(biāo)資源,顯然會(huì)導(dǎo)致不小的空間開銷搀玖,因此K8s引入了SharedInformer來(lái)解決這個(gè)問(wèn)題余境。

SharedInformer擁有為多個(gè)Controller提供一個(gè)共享cache的能力,從而避免資源緩存的重復(fù)灌诅、減小空間開銷芳来。除此之外,一個(gè)SharedInformer對(duì)一種資源只建立一個(gè)與API Server的Watch監(jiān)聽延塑,且能夠?qū)⒈O(jiān)聽得到的事件分發(fā)給下游所有感興趣的Controller绣张,這也顯著地減少了API Server的負(fù)載壓力答渔。實(shí)際上关带,K8s中廣泛使用的都是SharedInformer,Informer則出場(chǎng)甚少沼撕。

SharedIndexInformer

SharedIndexInformer 擴(kuò)展了 SharedInformer 接口宋雏,提供了構(gòu)建索引的能力。

SharedIndexInformerFactory

使用sharedInformerFactory可以統(tǒng)一管理控制器中需要的各資源對(duì)象的informer實(shí)例务豺,避免同一個(gè)資源創(chuàng)建多個(gè)實(shí)例

默認(rèn)的 Informer 實(shí)現(xiàn)

Informer 機(jī)制為 K8s 的各種對(duì)象提供了默認(rèn)的 Informer 實(shí)現(xiàn)磨总,可以通過(guò)以下方式快速創(chuàng)建一個(gè) Informer 對(duì)象,并交由 SharedIndexInformerFactory 統(tǒng)一管理笼沥。

SharedInformerFactory.Core().V1().Nodes()
.Core().V1().Pods()
.Apps().V1().Deployments()
.Core().V1().Secrets()
.Batch().V1beta1().CronJobs()

List-Watch相關(guān)

Reflector

Reflector用來(lái)watch特定的k8s API資源蚪燕。具體的實(shí)現(xiàn)是通過(guò)ListAndWatch的方法,watch可以是k8s內(nèi)建的資源或者是自定義的資源奔浅。當(dāng)reflector通過(guò)watch API接收到有關(guān)新資源實(shí)例存在的通知時(shí)馆纳,它使用相應(yīng)的列表API獲取新創(chuàng)建的對(duì)象,并將其放入watchHandler函數(shù)內(nèi)的Delta Fifo隊(duì)列中汹桦。

ListerWatcher

ListerWatcher 是 Informer 機(jī)制中的核心對(duì)象之一鲁驶,其功能是通過(guò) List() 方法從 API Server 中獲取某一類型的全量數(shù)據(jù),再通過(guò) Watch() 方法監(jiān)聽 API Server 中數(shù)據(jù)的增量更新舞骆。

ListerWatcher 繼承自 Lister 和 Watcher 接口钥弯,從而使其既能獲取全量數(shù)據(jù)径荔,又能監(jiān)聽增量數(shù)據(jù)更新。

Lister

Lister 接口用于完成全量數(shù)據(jù)的初始化脆霎。

Watcher

Watcher 接口用于監(jiān)聽數(shù)據(jù)的增量更新总处。

事件隊(duì)列相關(guān)

image.png

Store

Store是一個(gè)通用的對(duì)象存儲(chǔ)接口,其中定義了一系列與對(duì)象增刪改查相關(guān)的方法睛蛛。Store 要求對(duì)象有唯一鍵辨泳,鍵的計(jì)算方式由接口實(shí)現(xiàn)類中關(guān)聯(lián)的 KeyFunc 決定的。

Queue

從 Queue 接口的定義可以看出玖院,它繼承自 Store 接口菠红,所以其具備基本的數(shù)據(jù)存取能力。同時(shí)难菌,它又具備從隊(duì)列頭部取出數(shù)據(jù)并調(diào)用 PopProcessFunc 處理頭部數(shù)據(jù)并返回處理結(jié)果的能力试溯。

DeltaFIFO

DeltaFIFO 是一個(gè)生產(chǎn)者-消費(fèi)者的隊(duì)列,生產(chǎn)者是 Reflector郊酒,消費(fèi)者是 Pop 函數(shù)遇绞,從架構(gòu)圖上可以看出 DeltaFIFO 的數(shù)據(jù)來(lái)源為 Reflector,通過(guò) Pop 操作消費(fèi)數(shù)據(jù)燎窘,消費(fèi)的數(shù)據(jù)一方面存儲(chǔ)到 Indexer 中摹闽,另一方面可以通過(guò) Informer 的 handler 進(jìn)行處理,Informer 的 handler 處理的數(shù)據(jù)需要與存儲(chǔ)在 Indexer 中的數(shù)據(jù)匹配褐健。需要注意的是付鹿,Pop 的單位是一個(gè) Deltas,而不是 Delta蚜迅。

Delta

Delta 是 DeltaFIFO 存儲(chǔ)的類型舵匾,它記錄了對(duì)象發(fā)生了什么變化以及變化后對(duì)象的狀態(tài)。如果變更是刪除谁不,它會(huì)記錄對(duì)象刪除之前的最終狀態(tài)坐梯。

Deltas

Deltas 保存了對(duì)象狀態(tài)的變更(Add/Delete/Update)信息(如 Pod 的刪除添加等),Deltas 緩存了針對(duì)相同對(duì)象的多個(gè)狀態(tài)變更信息刹帕,如 Pod 的 Deltas[0]可能更新了標(biāo)簽吵血,Deltas[1]可能刪除了該 Pod。最老的狀態(tài)變更信息為 Oldest()偷溺,最新的狀態(tài)變更信息為 Newest()蹋辅,使用中,獲取 DeltaFIFO 中對(duì)象的 key 以及獲取 DeltaFIFO 都以最新狀態(tài)為準(zhǔn)亡蓉。

最舊的 delta 在索引0位置晕翠,最新的 delta 在最后一個(gè)索引位置。

DeltaType

const (
Added DeltaType = "Added" // 增加
Updated DeltaType = "Updated" // 更新
Deleted DeltaType = "Deleted" // 刪除
Sync DeltaType = "Sync" // 同步
)</pre>

DeltaFIFO 中數(shù)據(jù)存儲(chǔ)形式

image.png

事件處理相關(guān)

Controller

Processor

image.png
image.png

[圖片上傳失敗...(image-25a1a1-1637847474305)]

ResourceEventHandler

當(dāng)經(jīng)過(guò)List & Watch得到事件時(shí),接下來(lái)的實(shí)際響應(yīng)工作就交由ResourceEventHandler來(lái)進(jìn)行淋肾,這個(gè)Interface定義如下:

type ResourceEventHandler interface {
// 添加對(duì)象回調(diào)函數(shù)
OnAdd(obj interface{})
// 更新對(duì)象回調(diào)函數(shù)
OnUpdate(oldObj, newObj interface{})
// 刪除對(duì)象回調(diào)函數(shù)
OnDelete(obj interface{})
}

當(dāng)事件到來(lái)時(shí)硫麻,Informer根據(jù)事件的類型(添加/更新/刪除資源對(duì)象)進(jìn)行判斷,將事件分發(fā)給綁定的EventHandler樊卓,即分別調(diào)用對(duì)應(yīng)的handle方法(OnAdd/OnUpdate/OnDelete)拿愧,最后EventHandler將事件發(fā)送給Workqueue。

緩存相關(guān)

image.png

Indexer

Indexer在Store基礎(chǔ)上擴(kuò)展了索引能力碌尔,就好比給數(shù)據(jù)庫(kù)添加的索引浇辜,以便查詢更快,那么肯定需要有個(gè)結(jié)構(gòu)來(lái)保存索引唾戚。典型的索引用例是基于對(duì)象標(biāo)簽創(chuàng)建索引柳洋。 Indexer可以根據(jù)多個(gè)索引函數(shù)維護(hù)索引。Indexer使用線程安全的數(shù)據(jù)存儲(chǔ)來(lái)存儲(chǔ)對(duì)象及其鍵叹坦。 在Store中定義了一個(gè)名為MetaNamespaceKeyFunc 的默認(rèn)函數(shù)熊镣,該函數(shù)生成對(duì)象的鍵作為該對(duì)象的<namespace> / <name>組合。

Reflector 通過(guò) ListAndWatch 把數(shù)據(jù)傳入 DeltaFIFO 后募书,經(jīng)過(guò) DeltaFIFO 的 Pop 函數(shù)將資源對(duì)象存入到了本地的一個(gè)存儲(chǔ) Indexer 中绪囱,而這個(gè)底層真正的存儲(chǔ)其實(shí)就是上面的 ThreadSafeStore。

image.png

ThreadSafeStore

使用示例

var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String(, , "absolute path to the kubeconfig file")
}
flag.Parse()

config, err := clientcmd.BuildConfigFromFlags(, *kubeconfig)
if err != nil {
panic(err)
}

// 初始化 client
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Panic(err.Error())
}

stopper := make(chan struct{})
defer close(stopper)

// 初始化 informer
factory := informers.NewSharedInformerFactory(clientset, 0)
nodeInformer := factory.Core().V1().Nodes()
informer := nodeInformer.Informer()
defer runtime.HandleCrash()

// 啟動(dòng) informer莹捡,list & watch
go factory.Start(stopper)

// 從 apiserver 同步資源鬼吵,必不可少
if !cache.WaitForCacheSync(stopper, informer.HasSynced) {
runtime.HandleError(fmt.Errorf("Timed out waiting for caches to sync"))
return
}

// 使用自定義 handler
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: onAdd,
UpdateFunc: func(interface{}, interface{}) { fmt.Println("update not implemented") }, // 此處省略 workqueue 的使用
DeleteFunc: func(interface{}) { fmt.Println("delete not implemented") },
})

實(shí)現(xiàn)原理

構(gòu)建過(guò)程

image.png

啟動(dòng)過(guò)程

image.png

List 過(guò)程

image.png

Watch過(guò)程

image.png

變更分發(fā)過(guò)程

image.png

變更處理過(guò)程(待補(bǔ)充)

完整流程

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市篮赢,隨后出現(xiàn)的幾起案子齿椅,更是在濱河造成了極大的恐慌,老刑警劉巖荷逞,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件媒咳,死亡現(xiàn)場(chǎng)離奇詭異粹排,居然都是意外死亡种远,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門顽耳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)坠敷,“玉大人,你說(shuō)我怎么就攤上這事射富∠ビ” “怎么了车胡?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵罐旗,是天一觀的道長(zhǎng)欺抗。 經(jīng)常有香客問(wèn)我匀奏,道長(zhǎng)完域,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任捞魁,我火速辦了婚禮仅父,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘羊始。我一直安慰自己旱幼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布突委。 她就那樣靜靜地躺著柏卤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匀油。 梳的紋絲不亂的頭發(fā)上缘缚,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音敌蚜,去河邊找鬼忙灼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钝侠,可吹牛的內(nèi)容都是我干的该园。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼帅韧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼里初!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起忽舟,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤双妨,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后叮阅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刁品,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年浩姥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挑随。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勒叠,死狀恐怖兜挨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情眯分,我是刑警寧澤拌汇,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站弊决,受9級(jí)特大地震影響噪舀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一与倡、第九天 我趴在偏房一處隱蔽的房頂上張望先改。 院中可真熱鬧,春花似錦蒸走、人聲如沸仇奶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)该溯。三九已至,卻和暖如春别惦,著一層夾襖步出監(jiān)牢的瞬間狈茉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工掸掸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氯庆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓扰付,卻偏偏與公主長(zhǎng)得像堤撵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子羽莺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容