k8s-client-go源碼剖析(二)

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡介:雲原生社區活動---Kubernetes源碼剖析第一期第二週"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本週是K8S源碼研習社第一期第二週,學習內容是學習Informer機制,本文以這個課題進行展開。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本週研習社社長挺忙的,將本次課程推遲到下一週結束,任何事情都是這樣,計劃總有可能會被其他事情打破,但最終只要能夠迴歸到對應的主線上,就不是什麼問題。就像參與開源一樣,最開始的開放源代碼只是開始,需要的是能夠堅持下去,而這一點往往是很重要的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好了,開始正文。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"本文主題:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"Informer機制架構設計總覽"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"Reflector理解"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"DeltaFIFO理解"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"Indexer理解"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果涉及到資源的內容,本文以Deployment資源進行相關內容講述。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Informer機制架構設計總覽"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面是我根據理解畫的一個數據流轉圖,從全局視角看一下數據的整體走向是怎麼樣的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中虛線的表示的是代碼中的方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cd/cdfa3b3ec2e148308bc37db0d5931277.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先講一個結論:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過Informer機制獲取數據的情況下,在初始化的時候會從Kubernetes API Server獲取對應Resource的全部Object,後續只會通過Watch機制接收API Server推送過來的數據,不會再主動從API Server拉取數據,直接使用本地緩存中的數據以減少API Server的壓力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Watch機制基於HTTP的Chunk實現,維護一個長連接,這是一個優化點,減少請求的數據量。第二個優化點是SharedInformer,它可以讓同一種資源使用的是同一個Informer,例如v1版本的Deployment和v1beta1版本的Deployment同時存在的時候,共享一個Informer。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面圖中可以看到Informer分爲三個部分,可以理解爲三大邏輯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中Reflector主要是把從API Server數據獲取到的數據放到DeltaFIFO隊列中,充當生產者角色。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SharedInformer主要是從DeltaFIFIO隊列中獲取數據並分發數據,充當消費者角色。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後Indexer是作爲本地緩存的存儲組件存在。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Reflector理解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Reflector中主要看Run、ListAndWatch、watchHandler三個地方就足夠了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"源碼位置是 tools/cache/reflector.go"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"// Ruvn starts a watch and handles watch events. Will restart the watch if it is closed.\n// Run will exit when stopCh is closed.\n//開始時執行Run,上一層調用的地方是 controller.go中的Run方法\nfunc (r *Reflector) Run(stopCh 0 {\n\t\t... \n //pop消息\n \n\t\tf.cond.Broadcast()\n\t...\n\treturn nil\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Pop方法:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"func (f *DeltaFIFO) Pop(process PopProcessFunc) (interface{}, error) {\n\tf.lock.Lock()\n\tdefer f.lock.Unlock()\n\tfor {\n\t\tfor len(f.queue) == 0 {\n\t\t\t//阻塞 直到調用了f.cond.Broadcast()\n\t\t\tf.cond.Wait()\n\t\t}\n//取出第一個元素\n\t\tid := f.queue[0]\n\t\tf.queue = f.queue[1:]\n\t\t...\n\t\titem, ok := f.items[id]\n...\n delete(f.items, id)\n\t\t//這個process可以在controller.go中的processLoop()找到\n\t\t//初始化是在shared_informer.go的Run\n\t\t//最終執行到shared_informer.go的HandleDeltas方法\n\t\terr := process(item)\n\t\t//如果處理出錯了重新放回隊列中\n\t\tif e, ok := err.(ErrRequeue); ok {\n\t\t\tf.addIfNotPresent(id, item)\n\t\t\terr = e.Err\n\t\t}\n\t\t ...\n\t}\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Resync機制:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"小總結:每次從本地緩存Indexer中獲取數據重新放到DeltaFIFO中執行任務邏輯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"啓動的Resync地方是reflector.go的resyncChan()方法,在reflector.go的ListAndWatch方法中的調用開始定時執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"go func() {\n //啓動定時任務\n\t\tresyncCh, cleanup := r.resyncChan()\n\t\tdefer func() {\n\t\t\tcleanup() // Call the last one written into cleanup\n\t\t}()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase %s\\n\", idx+1, deploy.Name)\n\t}\n\n\t
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章