以閱讀k8s其中的一個模塊,scheduler爲例子,來說講我是怎麼讀代碼的java
scheduler是k8s的調度模塊,作的事情就是拿到pod以後在node中尋找合適的進行適配這麼一個單純的功能。實際上,我已經屢次編譯和構建這個程序並運行起來。在個人腦中,sheduler在整個系統中是這樣的:node
scheduler做爲一個客戶端,從apiserver中讀取到須要分配的pod,和擁有的node,而後進行過濾和算分,最後把這個匹配信息經過apiserver寫入到etcd裏面,供下一步的kubelet去拉起pod使用。這樣,馬上有幾個問題浮現出來git
問1.scheduler讀取到的數據結構是怎麼樣的?(輸入)
問2.scheduler寫出的的數據結構是怎麼樣的?(輸出)
問3.在前面的測試中,scheduler成爲了系統的瓶頸,爲何?
問4.社區有人說增長緩存能有效提升scheduler的效率,他的思路是可行的嗎?github
kubernetes\plugin\cmd\kube-scheduler\scheduler.go
這段代碼比較短就全文貼出來了redis
package main import ( "runtime" "k8s.io/kubernetes/pkg/healthz" "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/version/verflag" "k8s.io/kubernetes/plugin/cmd/kube-scheduler/app" "github.com/spf13/pflag" ) func init() { healthz.DefaultHealthz() //忽略…… } func main() { runtime.GOMAXPROCS(runtime.NumCPU()) //忽略…… s := app.NewSchedulerServer() //關注,實際調用的初始化 s.AddFlags(pflag.CommandLine) //忽略,命令行解析 util.InitFlags() util.InitLogs() defer util.FlushLogs() //忽略,開日誌等 verflag.PrintAndExitIfRequested() s.Run(pflag.CommandLine.Args()) //關注,實際跑的口子 }
能夠看到,對於細枝末節我一律忽略掉,進入下一層,可是,我並非不提出問題,提出的問題會寫在這裏,而後從腦子裏面「忘掉」,以減輕前進的負擔算法
kubernetes\plugin\cmd\kube-scheduler\app\server.go
進入這個文件後,重點看的就是數據結構和方法:api
SchedulerServer
這個結構存放了一堆配置信息,裸的,能夠看到裏面幾個成員變量都是基本類型,int, string等AlgorithmProvider
來建立具體算法的調度器。再下一層的入口在:緩存
sched := scheduler.New(config) sched.Run()
對於這層的問題是:
問5.幾個限流是怎麼實現的?QPS和Brust有什麼區別?
問6.算法提供者AlgorithmProvider
是怎麼被抽象出來的?須要完成什麼事情?數據結構
答5.在翻了限流的代碼後,發現來自於kubernetes\Godeps\_workspace\src\github.com\juju\ratelimit
,實現的是一個令牌桶的算法,burst指的是在n個請求內保持qps平均值的度量。詳見這篇文章架構
kubernetes\plugin\pkg\scheduler\scheduler.go
答2:在這裏我看到了輸出的數據結構爲:
b := &api.Binding{ ObjectMeta: api.ObjectMeta{Namespace: pod.Namespace, Name: pod.Name}, Target: api.ObjectReference{ Kind: "Node", Name: dest, }, }
這個文件最重要的數據結構是:
type Config struct { // It is expected that changes made via modeler will be observed // by NodeLister and Algorithm. Modeler SystemModeler NodeLister algorithm.NodeLister Algorithm algorithm.ScheduleAlgorithm Binder Binder // Rate at which we can create pods // If this field is nil, we don't have any rate limit. BindPodsRateLimiter util.RateLimiter // NextPod should be a function that blocks until the next pod // is available. We don't use a channel for this, because scheduling // a pod may take some amount of time and we don't want pods to get // stale while they sit in a channel. NextPod func() *api.Pod // Error is called if there is an error. It is passed the pod in // question, and the error Error func(*api.Pod, error) // Recorder is the EventRecorder to use Recorder record.EventRecorder // Close this to shut down the scheduler. StopEverything chan struct{} }
數據結構是什麼?數據結構就是舞臺上的角色,而函數方法就是這些角色之間演出的一幕幕戲。對象是有生命的,從建立到數據流轉,從產生到消亡。而做爲開發者來講,首先是搞懂這些人物設定,是關公仍是秦瓊,是紅臉仍是黑臉?看懂了人,就看懂了戲。
這段代碼裏面,結合下面的方法,我能夠得出這麼幾個印象:
問7.結合觀看了modeler.go
以後,發現這是在綁定後處理的,所謂的assuemPod,就是把綁定的pod放到一個隊列裏面去,不是很理解爲何這個互斥操做是放在bind以後作?
問8.Binder是怎麼去作綁定操做的?
下一層入口:
dest, err := s.config.Algorithm.Schedule(pod, s.config.NodeLister)
kubernetes\plugin\pkg\scheduler\generic_scheduler.go
在調到這一層的時候,我發現本身走過頭了,上面s.config.Algorithm.Schedule
並不會直接調用generic_scheduler.go
。對於一門面向對象的語言來講,最後的執行多是一層接口套一層接口,而接口和實現的分離也形成了當你閱讀到某個地方以後就沒法深刻下去。或者說,純粹的自頂向下的閱讀方式並不適合面向對象的代碼。因此,目前個人閱讀方法開始變成了碎片式閱讀,先把整個代碼目錄樹給看一遍,而後去最有可能解釋我心中疑問的地方去尋找答案,而後一片片把真相拼合起來。
問9.generic_scheduler.go是怎麼和scehduler.go產生關係的?
這是代碼目錄樹:
從目錄樹中,能夠看出調度算法的目錄在algrorithem
和algrorithemprovider
裏面,而把對象組裝在一塊兒的關鍵源代碼是在:
答8.Binder的操做其實很簡單,就是把pod和node的兩個字段放到http請求中發送到apiserver去作綁定,這也和系統的總體架構是一致的
factory的最大做用,就是從命令行參數中獲取到--algorithm
和--policy-config-file
來獲取到必要算法名稱和調度策略,來構建Config,Config實際上是調度程序的核心數據結構。schduler這整個程序作的事情能夠歸納爲:獲取配置信息——構建Config——運行Config。這個過程相似於java中的sping組裝對象,只不過在這裏是經過代碼顯式進行的。從裝配工廠中,咱們看到了關鍵的一行
algo := scheduler.NewGenericScheduler(predicateFuncs, priorityConfigs, extenders, f.PodLister, r)
這樣就把我上面的問9解答了
答9.scheduler.go是形式,generic_scheduler.go是內容,經過factory組裝
也解答了問6
答6.factoryProvider僅僅是一個算法註冊的鍵值對錶達地,大部分的實現仍是放在generic_scheduler裏面的
這就涉及到調度的核心邏輯,就2行
filteredNodes, failedPredicateMap, err := findNodesThatFit().... priorityList, err := PrioritizeNodes()...
這裏我就不詳細敘述細節了,讀者能夠按照個人路子去本身尋找答案。