
今天給到大家介紹一下 Client-go 中的一個非常關鍵的工具包
Informer。 Informer 内部實作極其複雜,詳細介紹的文章也很少,很多人回報比較難用。但不得不承認它也是一個設計精良、安全可靠的元件,值得我們去一探究竟。
Informer 簡介
Informer 基礎功能
Informer 是 Client-go 中的一個核心工具包。在 Kubernetes 源碼中,如果 Kubernetes 的某個元件,需要 List/Get Kubernetes 中的 Object,在絕大多 數情況下,會直接使用 Informer 執行個體中的 Lister()方法(該方法包含 了 Get 和 List 方法),而很少直接請求 Kubernetes API。Informer 最基本 的功能就是 List/Get Kubernetes 中的 Object。
如下圖所示,僅需要十行左右的代碼就能實作對 Pod 的 List 和 Get。
Informer 進階功能
Client-go 的首要目标是滿足 Kubernetes 的自身需求。Informer 作為其中的核心工具包,面對 Kubernetes 極為複雜業務邏輯,如果僅實作 List/Get 功能,根本無法滿足 Kubernetes 自身需求。是以,Informer 被設計為一個靈活而複雜的工具包,除 List/Get Object 外,Informer 還可以監聽事件并觸發回調函數等,以實作更加複雜的業務邏輯。
Informer 設計思路
Informer 設計中的關鍵點
為了讓 Client-go 更快地傳回 List/Get 請求的結果、減少對 Kubenetes API 的直接調用,Informer 被設計實作為一個依賴 Kubernetes List/Watch API 、可監聽事件并觸發回調函數的二級緩存工具包。
更快地傳回 List/Get 請求,減少對 Kubenetes API 的直接調用
使用 Informer 執行個體的 Lister() 方法, List/Get Kubernetes 中的 Object 時,Informer 不會去請求 Kubernetes API,而是直接查找緩存在本地記憶體中的資料(這份資料由 Informer 自己維護)。通過這種方式,Informer 既可以更快地傳回結果,又能減少對 Kubernetes API 的直接調用。
依賴 Kubernetes List/Watch API
Informer 隻會調用 Kubernetes List 和 Watch 兩種類型的 API。Informer 在初始化的時,先調用 Kubernetes List API 獲得某種 resource 的全部 Object,緩存在記憶體中; 然後,調用 Watch API 去 watch 這種 resource,去維護這份緩存; 最後,Informer 就不再調用 Kubernetes 的任何 API。
用 List/Watch 去維護緩存、保持一緻性是非常典型的做法,但令人費解的是,Informer 隻在初始化時調用一次 List API,之後完全依賴 Watch API 去維護緩存,沒有任何 resync 機制。
筆者在閱讀 Informer 代碼時候,對這種做法十分不解。按照多數人思路,通過 resync 機制,重新 List 一遍 resource 下的所有 Object,可以更好的保證 Informer 緩存和 Kubernetes 中資料的一緻性。
咨詢過 Google 内部 Kubernetes 開發人員之後,得到的回複是:
在 Informer 設計之初,确實存在一個 relist 無法去執 resync 操作, 但後來被取消了。原因是現有的這種 List/Watch 機制,完全能夠保證永遠不會漏掉任何事件,是以完全沒有必要再添加 relist 方法去 resync informer 的緩存。這種做法也說明了 Kubernetes 完全信任 etcd。
可監聽事件并觸發回調函數
Informer 通過 Kubernetes Watch API 監聽某種 resource 下的所有事件。而且,Informer 可以添加自定義的回調函數,這個回調函數執行個體(即 ResourceEventHandler 執行個體)隻需實作 OnAdd(obj interface{}) OnUpdate(oldObj, newObj interface{}) 和 OnDelete(obj interface{}) 三個方法,這三個方法分别對應 informer 監聽到建立、更新和删除這三種事件類型。
在 Controller 的設計實作中,會經常用到 informer 的這個功能。 Controller 相關文章請見此文《
如何用 client-go 拓展 Kubernetes 的 API》。
二級緩存
二級緩存屬于 Informer 的底層緩存機制,這兩級緩存分别是 DeltaFIFO 和 LocalStore。
這兩級緩存的用途各不相同。DeltaFIFO 用來存儲 Watch API 傳回的各種事件 ,LocalStore 隻會被 Lister 的 List/Get 方法通路 。
雖然 Informer 和 Kubernetes 之間沒有 resync 機制,但 Informer 内部的這兩級緩存之間存在 resync 機制。
以上是 Informer 設計中的一些關鍵點,沒有介紹一些太細節的東西,尤其對于 Informer 兩級緩存還未做深入介紹。下一章節将對 Informer 詳細的工作流程做一個詳細介紹。
Informer 詳細解析
Informer 内部主要元件
Informer 中主要包含 Controller、Reflector、DeltaFIFO、LocalStore、Lister 和 Processor 六個元件,其中 Controller 并不是 Kubernetes Controller,這兩個 Controller 并沒有任何聯系;Reflector 的主要作用是通過 Kubernetes Watch API 監聽某種 resource 下的所有事件;DeltaFIFO 和 LocalStore 是 Informer 的兩級緩存;Lister 主要是被調用 List/Get 方法;Processor 中記錄了所有的回調函數執行個體(即 ResourceEventHandler 執行個體),并負責觸發這些函數。
Informer 關鍵邏輯解析
我們以 Pod 為例,詳細說明一下 Informer 的關鍵邏輯:
- Informer 在初始化時,Reflector 會先 List API 獲得所有的 Pod
- Reflect 拿到全部 Pod 後,會将全部 Pod 放到 Store 中
- 如果有人調用 Lister 的 List/Get 方法擷取 Pod, 那麼 Lister 會直接從 Store 中拿資料
-
Kubernetes Informer 詳解 - Informer 初始化完成之後,Reflector 開始 Watch Pod,監聽 Pod 相關 的所有事件;如果此時 pod_1 被删除,那麼 Reflector 會監聽到這個事件
- Reflector 将 pod_1 被删除 的這個事件發送到 DeltaFIFO
- DeltaFIFO 首先會将這個事件存儲在自己的資料結構中(實際上是一個 queue),然後會直接操作 Store 中的資料,删除 Store 中的 pod_1
- DeltaFIFO 再 Pop 這個事件到 Controller 中
-
Kubernetes Informer 詳解 - Controller 收到這個事件,會觸發 Processor 的回調函數
LocalStore 會周期性地把所有的 Pod 資訊重新放到 DeltaFIFO 中
Informer 總結
Informer 的内部原理比較複雜、不太容易上手,但 Informer 卻是一個非常穩定可靠的 package,已被 Kubernetes 廣泛使用。但是,目前關于 Informer 的文章不是很多,如果文章中有表述不正确的地方,希望各位讀者悉心指正。
本文轉自中文社群-
Kubernetes Informer 詳解