本文介紹了kubernetes針對etcd的watch場景,k8s在性能優化上面的一些設計,逐個介紹緩存、定時器、序列化緩存、bookmark機制、forget機制、針對數據的索引與ringbuffer等組件的場景以及解決的問題,但願能幫助到那些對apiserver中的watch機制實現感興趣的朋友前端
k8s中並無將業務的具體處理邏輯耦合在rest接口中,rest接口只負責數據的存儲,經過控制器模式,分離數據存儲與業務邏輯的耦合,保證apiserver業務邏輯的簡潔。 api
控制器經過watch接口來感知對應的資源的數據變動,從而根據資源對象中的指望狀態與當前狀態之間的差別,來決策業務邏輯的控制,watch本質上作的事情其實就是將感知到的事件發生給關注該事件的控制器緩存
這裏咱們先介紹基於etcd實現的基礎的watch模塊性能優化
一個數據變動本質上無非就是三種類型:新增、更新和刪除,其中新增和刪除都比較容易由於均可以經過當前數據獲取,而更新則可能須要獲取以前的數據,這裏其實就是藉助了etcd中revision和mvcc機制來實現,這樣就能夠獲取到以前的狀態和更新後的狀態,而且獲取後續的通知微信
事件管道則是負責事件的傳遞,在watch的實現中經過兩級管道來實現消息的分發,首先經過watch etcd中的key獲取感興趣的事件,並進行數據的解析,完成從bytes到內部事件的轉換而且發送到輸入管道(incomingEventChan)中,而後後臺會有線程負責輸入管道中獲取數據,並進行解析發送到輸出管道(resultChan)中,後續會從該管道來進行事件的讀取發送給對應的客戶端mvc
事件緩衝區是指的若是對應的事件處理程序與當前事件發生的速率不匹配的時候,則須要必定的buffer來暫存由於速率不匹配的事件, 在go裏面你們一般使用一個有緩衝的chan構建 函數
到這裏基本上就實現了一個基本可用的watch服務,經過etcd的watch接口監聽數據,而後啓動獨立goroutine來進行事件的消費,而且發送到事件管道供其餘接口調用源碼分析
kubernetes中全部的數據和系統都基於etcd來實現,如何減輕訪問壓力呢,答案就是緩存,watch也是這樣,本節咱們來看看如何實現watch緩存機制的實現,這裏的cacher是針對性能
Reflector是client-go中的一個組件,其經過listwatch接口獲取數據存儲在本身內部的store中,cacher中經過該組件從etcd進行watch操做,避免爲每一個組件都建立一個etcd的watch學習
wacthCache負責存儲watch到的事件,而且將watch的事件創建對應的本地索引緩存,同時在構建watchCache還負責將事件的傳遞,其將watch到的事件經過eventHandler來傳遞給上層的Cacher組件
cacheWatcher顧名思義其是就是針對cache的一個watcher(watch.Interface)實現, 前端的watchServer負責從起ResultChan裏面獲取事件進行轉發
Cacher基於etcd的store結合上面的watchCache和Reflector共同構建帶緩存的REST store, 針對普通的增刪改功能其直接轉發給etcd的store來進行底層的操做,而對於watch操做則進行攔截,構建並返回cacheWatcher組件
看完基礎組件的實現,接着咱們看下針對watch這個場景k8s中還作了那些優化,學習針對相似場景的優化方案
若是咱們有多個watcher都wacth同一個事件,在最終的時候咱們都須要進行序列化,cacher中在分發的時候,若是發現超過指定數量的watcher, 則會在進行dispatch的時候,爲其構建構建一個緩存函數,針對多個watcher只會進行一次的序列化
在上面咱們提到過事件緩衝區,可是若是某個watcher消費過慢依然會影響事件的分發,爲此cacher中經過是否阻塞(是否能夠直接將數據寫入到管道中)來將watcher分爲兩類,針對不能當即投遞事件的watcher, 則會在後續進行重試
針對阻塞的watcher在進行重試的時候,會經過dispatchTimeoutBudget構建一個定時器來進行超時控制, 那什麼叫Budget呢,其實若是在這段時間內,若是重試立馬就成功,則本次剩餘的時間,在下一次進行定時的時候,則可使用以前剩餘的餘額,可是後臺也還有個線程,用於週期性重置
針對上面的TimeBudget若是在給定的時間內依舊沒法進行重試成功,則就會經過forget來刪除對應的watcher, 由此針對消費特別緩慢的watcher則能夠經過後續的重試來從新創建watch,從而減少對apiserver的watch壓力
bookmark機制是大阿里提供的一種優化方案,其核心是爲了不單個某個資源一直沒有對應的事件,此時對應的informer的revision會落後集羣很大,bookmark經過構建一種BookMark類型的事件來進行revision的傳遞,從而讓informer再重啓後不至於落後特別多
watchCache中經過store來構建了對應的索引緩存,可是在listwatch操做的時候,則一般須要獲取某個revision後的全部數據,針對這類數據watchCache中則構建了一個ringbuffer來進行歷史數據的緩存
本文介紹了kubernetes針對etcd的watch場景,k8s在性能優化上面的一些設計,逐個介紹緩存、定時器、序列化緩存、bookmark機制、forget機制、針對數據的索引與ringbuffer等組件的場景以及解決的問題,但願能幫助到那些對apiserver中的watch機制實現感興趣的朋友
kubernetes學習筆記地址: https://www.yuque.com/baxiaoshi/tyado3
> 微信號:baxiaoshi2020
> 關注公告號閱讀更多源碼分析文章