日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網營銷解決方案
從ListWatch到WatchList

分析

可以先設想一下如果自己去實現(xiàn)的話,該如何設計。Client 和 Server 端都要去適配這是必然的,因為 Informer 現(xiàn)在是 ListWatch 機制,服務端并不支持流式 List。因此可以有個初步的方向:

成都創(chuàng)新互聯(lián)-專業(yè)網站定制、快速模板網站建設、高性價比昆都侖網站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式昆都侖網站制作公司更省心,省錢,快速模板網站建設找我們,業(yè)務覆蓋昆都侖地區(qū)。費用合理售后完善,10余年實體公司更值得信賴。

  1. Server 端支持流式 List 請求
  2. Informer 適配 Server 端 API 的變化

客戶端的適配相對簡單,重點還是放在 Server 端如何實現(xiàn)。先回顧下之前 List 的邏輯,在前一篇 Stale Read 里面已經介紹過了。

為方面描述,下文統(tǒng)一使用 RV 代指 Resourceversion,本節(jié)邏輯均基于 v1.26.9 版本,且忽略分頁查詢,因為分頁是直接走 Etcd 的。

無論是 List 還是 Watch 請求,其 query 均支持傳入 RV,服務端會根據(jù)請求的 RV 的不同做相應的處理,根據(jù) RV 的值可以分為三種情況

  1. 未設置或者顯示設置 RV=""
  2. RV = "0"
  3. RV = "非 0 值"

對于前兩種情況,List 會直接返回 WatchCache Store 中的內容,即服務端緩存好的 Etcd 的全部相關數(shù)據(jù)。

對于第三種情況,會等待服務端緩存數(shù)據(jù)的最大版本要超過傳入的 RV 之后再返回緩存內的數(shù)據(jù),如果等待了一段時間(3s)后緩存中的數(shù)據(jù)仍然沒有達到指定版本,則會報錯返回 "Too large resource version",并告訴客戶端可以在 1s 之后重試。

新版中已經修復了 List Stale Read 的問題,對于前兩種情況,其會先從 kube-apiserver 獲取 Etcd 最新的 RV,等待 WatchCache Store 內容追平 RV 后再一次性的返回。

也就是說服務端是可以知道自己是否已經包含最新全量數(shù)據(jù)的,在這個基礎上再以流式方式返回即可。當前已有的流式 API 就是 Watch,所以可以在此基礎上支持 List 的效果。為什么不直接在 List 請求基礎上改呢,因為改 List 的話,會涉及到太多的客戶端側的適配,List 會經常單獨使用,而 Watch 基本是在 Informer 里面使用。

所以最終的工作就會變成如何使用 Watch API 實現(xiàn) List 的效果,但數(shù)據(jù)仍然以流式返回給客戶端,同時 Informer 修改 ListWatch 方式為只使用 Watch API 實現(xiàn)之前的效果。下文以詳細介紹服務端實現(xiàn)為主,客戶端適配的部分會比較簡單的介紹下。

原理

通過為 Watch API 添加一個 SendInitialEvents=true 參數(shù)來支持 List 的效果。Server 端接收到 Watch 請求后判斷哪些數(shù)據(jù)是應該作為 InitEvents 發(fā)送給客戶端,同時在發(fā)送完這些數(shù)據(jù)之后發(fā)送一個特定的 BOOKMARK Event(帶特定 Annotation 的 BOOKMARK,其 RV 對應下文的 bookmarkAfterRV)給客戶端作為服務端通知客戶端 InitEvents 發(fā)送完畢的標志,客戶端在接收到指定 BOOKMARK Event 后,將之前接收到的所有 InitEvent 作為 List 的結果處理。

時序圖

下面是基于 v1.29 代碼的分析,此時 v1.29 還在 alpha 狀態(tài),提到的舊版代表 1.27 之前的版本,新版代表 v1.29。如果你看到的代碼和下面描述的不一致,有可能是代碼版本導致的。

圖片

從 WatchCache 開始右面四個藍色的是在 kube-apiserver 啟動的時候開始執(zhí)行的,G1 G2 代表兩個 goroutine,分別用來從 Etcd 獲取數(shù)據(jù),以及發(fā)送數(shù)據(jù)給客戶端 CacheWatcher 的 input chan

  1. G1.1 每種資源類型對應一個 Cacher,內部包含一個 Reflector,WatchCache 作為 Reflector 的 Store 存儲從 Etcd 獲取到的數(shù)據(jù);
  2. G1.2 Reflector 開啟調用 Etcd List 和 Watch API 獲取數(shù)據(jù);
  3. G1.3 Reflector 利用獲取到的數(shù)據(jù)更新 WatchCache 的 store 和 cyclic buffer,兩者分別用來存儲全量的對象和對象的最近更新事件;
  4. G1.4 在更新完 WatchCache 后,會把 Event 發(fā)送到 Cacher 的 incoming chan 中;
  5. G2.1 從 Cacher 的 imcomming chan 中消費數(shù)據(jù)發(fā)送給所有的 CacheWatcher 的 input chan,或者定時(1 ~ 1.25s)發(fā)送 RV > bookmarkAfterRV 的 BOOKMARK 事件給所有的 CacheWatcher 的 input chan;

上述過程描述了服務端啟動時的數(shù)據(jù)處理流程,接下來看有客戶端請求時的處理流程

  1. Reflector 首次發(fā)起 Watch 請求,query 中指定 RV=""&sendInitialEvent=true&resourceVersinotallow=NotOlderThan&AllowWatchBookmarks=true,這里無論 RV="" 還是 RV="0" 都可以實現(xiàn) List 的效果,只不過相比舊版本的實現(xiàn),新版里面 Watch 請求針對 RV="" 做了特殊處理,解決了 Watch API Stale Read 的問題(List Stale Read 已經在前一篇中介紹過了,針對 List 提供了 FeatureGate 來控制是否開啟 Consistent Read,但 Watch 這里并沒有對應的 FeatureGate,也即是說新版中針對 RV="" 的請求一定是 Consistent Read),服務端接收到請求后為這個請求創(chuàng)建對應的 CacheWachter 對象;
  2. Server 端在接收到請求后計算 bookmarkAfterRV 的值,如果 RV="0",則 bookmarkAfterRV 就是 WatchCache RV(WatchCache Store 數(shù)據(jù)中的最大 RV),如果 RV="",則去 Etcd 中獲取最大的 RV 作為 bookmarkAfterRV,將 bookmarkAfterRV 傳遞給 CacheWatcher,最后 CacheWatcher 會結合 WatchCache Store 和自身 input chan 中的數(shù)據(jù)準備 InitEvents

2a 開始從 WatchCache Store 中獲取需要返回的數(shù)據(jù),此時的處理邏輯舊版本相同,返回 Store 中的全部數(shù)據(jù),并記錄 Store 數(shù)據(jù)的最大 RV 供下一步使用;

2b 消費 input chan 中的事件,對比其 RV 是否比 2a 傳入的 RV 大,或者如果是 BOOKMARK 類型并且 RV 等與 2a 傳入的 RV,且尚未發(fā)送 bookmarkAfterRV 的事件,則此 BOOKMARK 事件就會被當做 List 結束的標志,為其設置 Annotation: k8s.io/initial-events-end,最后發(fā)送給客戶端;

至此,服務端的主要流程已經介紹完,客戶端 Informer 也做了對應的適配,如果開啟 WathList 功能的話,會發(fā)送 Watch 請求來獲取一遍全量數(shù)據(jù),等到接收到攜帶 Annotation: k8s.io/initial-events-end 的 BOOKMARK 事件后,記錄其 RV,將在此期間接受并處理后的對象作為 List 的結果。最后再次以上述 RV 作為參數(shù)調用 Watch 請求,從這一步開始就是 Informer 傳統(tǒng)意義上的 Watch 邏輯了。

數(shù)據(jù)流

圖片

圖片來自 KEP 3157 watch-list,其實里面也包含時序圖,不過里面的書序圖畫的有一些問題,和代碼不一致,所以這里并沒有直接使用他的時序圖,而是重新畫了。

可以結合上面兩個圖理解整個過程,上圖中的 a 對應時序圖中的 2a,b 對應時序圖中的 2b,c 對應時序圖中的 G2.1。最下面白色部分對應時序圖中 G1 的邏輯,即從 Etcd 獲取數(shù)據(jù),客戶端請求的處理是自上到下的,而數(shù)據(jù)返回是自下而上的。

注意

上述處理邏輯中存在很多的細節(jié),需要額外注意下

  1. 為 Watch API 修復了 Stale Read 的問題(RV="" WatchList 功能),本質上也是消除 List 的 Stale Read,只不過是在 Watch API 中實現(xiàn)的,這樣結合上一篇,不管是直接使用 List API 還是使用 WatchList 都能避免 Stale Read 的問題;
  2. WatchCache Store 中的數(shù)據(jù)和 Cacher imcomming chan 數(shù)據(jù)是有交叉的,所以在 2a 處理完所有 Store 數(shù)據(jù)后記錄了最大的 RV 傳遞給 2b 在處理 imcomming chan 的數(shù)據(jù)時使用,event RV > RV 的非 BOOKMARK 事件才會發(fā)回客戶端,這樣是為了避免時間回流;
  3. CacheWatcher 的 input chan 中是不存在 RV < bookmarkAfterRV 的事件的,在 G2.1 從 Cacher incoming chan 消費并發(fā)往所有 CacheWatcher input 的時候判斷了如果事件類型是 BOOKMARK 且 RV < bookmarkAfterRV,則直接丟棄此事件,因為 input chan 緩沖區(qū)大小有限,在其創(chuàng)建后 Cacher 就開始往其 input 寫數(shù)據(jù),而開始消費 input chan 是在 2a 處理完所有 Store 中的數(shù)據(jù)之后,中間存在一段時間差,事件的長短和 Store 中的數(shù)據(jù)量有關系,丟棄不必要的 BOOKMARK 事件就可以緩解 input chan 的壓力,這里涉及到了為 input chan 添加事件的處理邏輯,里面包括多種特殊情況的處理,例如緩沖滿了如何處理避免因為單個 CacheWatcher 而阻塞整個流程,發(fā)數(shù)據(jù)異常如何處理;
  4. 最終發(fā)回給客戶端的攜帶特定 Annotation 的 BOOKMARK 事件的 RV >= bookmarkAfterRV,這里非常值得注意,并不是等于 bookmarkAfterRV,原 KEP 時序圖中此處(2c)的描述是錯誤的。根本原因在于 bookmark timer 的周期為 1 ~ 1.25s,也就是說每 1 ~ 1.25s 產生一個 BOOKMARK 事件,其 RV 是 incoming chan 最大 RV,正是由于這個時間間隔,結合 3 的描述,就會導致 G2.1 發(fā)送出去的第一個有效的 (進入到 CacheWatcher input chan) BOOKMARK 事件的 RV >= bookmarkAfterRV。這也從側面說明了最終在返回 bookmarkAfterRV BOOKMARK 事件之前返回的所有的攜帶有效負載的事件集合的最大 RV 也是 >= bookmarkAfterRV 的,即雖然標記是 bookmarkAfterRV,但 List 的結果中包含比 bookmarkAfterRV 大的數(shù)據(jù)。 個人認為此處還是可以再繼續(xù)優(yōu)化的,可以讓 List 的耗時減少一個 bookmark timer 的周期,即 1 ~ 1.25s,只需要在 2b 處理非 BOOKMARK 事件時判斷 RV == bookmarkAfterRV 且尚未發(fā)送過 bookmarkAfterRV BOOKMARK 事件,此時就可以直接返回一個 bookmarkAfterRV BOOKMARK 給客戶端了,對于數(shù)據(jù)量較大,返回所有數(shù)據(jù)耗時超過 Watch timeout 時間 1s 左右時可以降低超時的概率,避免重復執(zhí)行 WatchList 的過程,也能在一定程度上降低內存消耗。

總結

本篇主要分析了 WatchList 的實現(xiàn)原理和邏輯,其中不乏一些細節(jié)處理,后續(xù)也會和社區(qū)就有關細節(jié)進一步討論。在此 KEP 中同時還介紹了另外兩個用來降低 kube-apiserver 內存壓力的修改,篇幅有限,將會在下一篇中進行介紹,同時也會給出所有優(yōu)化工作做完前后的效果對比。敬請期待~


名稱欄目:從ListWatch到WatchList
網址分享:http://www.dlmjj.cn/article/djsdosd.html