天天看點

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

目錄

第一節 main函數

第二節 建立server

建立ListenerManager

建立ClusterManager

第三節 啟動server

envoy在處理請求時用到的主要的元件為Listener和Cluster,Listener負責監聽downstream發送的請求,Listener監聽到downstream發送的請求後,由Cluster來選擇upstream中的某個端點來處理該請求,最終Listener将端點的回複資訊傳回到downstream,其架構圖如下所示:

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

 Listener,Cluster在系統啟動時會根據其配置被初始化。  Listener,Cluster和系統其餘元件構成了一個完整的伺服器,當所有這些元件初始化成功後,envoy伺服器也初始化成功了,運作中的伺服器可以不斷的利用Listener,Cluster等元件來完成其工作。

envoy有一個基于事件的線程模型,主線程會管理envoy伺服器的生命周期,配置處理,運作狀态等,其餘還有一些工作線程,這些工作線程用來處理各種網絡請求。所有線程都圍繞一個事件循環(libevent)操作,任何給定的downstream的TCP連接配接(包括其上的所有多路複用流)在其生命周期内都将由一個工作線程處理。每個工作線程會維護一個到 upstream的端點的TCP連接配接池。

接下來通過分析envoy的啟動過程源碼來看envoy是怎麼建立其伺服器的。

envoy源碼位址:https://github.com/envoyproxy/envoy.git

第一節 main函數

envoy實作main函數的檔案為source/exe/main.cc,main函數調用MainCommon::main實作了envoy的啟動,MainCommon::main的代碼如下所示:

source/exe/main_common.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

  圖1-1

第234,235行代碼一起執行個體化了一個server,255行代碼啟動該server,至此,envoy就啟動起來了。

第二節 建立server

envoy通過啟動一個伺服器server來工作,該server由各種元件組成,這裡最關鍵的元件就是用于管理系統中的監聽器listener的監聽管理器ListenerManager,用來管理叢集cluster的叢集管理器ClusterManager,  server在初始化時會初始化這些元件。

第一節中234,235建立server時最終調用的server建立代碼如下:

 source/exe/main_common.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-1

 這裡是調用的Server::InstanceImpl類的構造函數構造了server的執行個體,下面來分析Server::InstanceImpl類的構造函數,代碼如下所示:

source/server/server.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-2

Server::InstanceImpl類構造了server對象,并建立了該server需要的所有元件,比如用于管理系統中的監聽器listener的監聽管理器ListenerManager,用來管理叢集cluster的叢集管理器ClusterManager等。

 95行:建立并初始化檔案日志系統,用于管理日志;

105行:初始化envoy的熱重新開機功能子產品,用于管理envoy伺服器的熱重新開機;

106行:初始化一個DrainManager,這個在伺服器熱重新開機或者動态删除Listener時會使用

107行:Server::InstanceImpl構造函數調用initialize來建立伺服器的其餘元件,監聽管理器ListenerManager和叢集管理器ClusterManager也是在這裡建立的。

initialize核心代碼如下所示:

source/server/server.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-3

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-4

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-5

346行:從配置檔案中加載bootstrap資訊

510行:建立ListenerManager來管理Listener

591行:通過從配置檔案加載出來的bootstrap資訊來建立靜态的ClusterManager和listener

609行:初始化靜态ClusterManager

建立ListenerManager

ListenerManager擁有一個或多個工作線程,每個工作線程會去處理一個給定的downstream的TCP連接配接,它會維護一個到 upstream的端點的TCP連接配接池。ListenerManager負責建立這些工作線程,工作線程建立好了以後ListenerManager就建立完成了。

上文中ListenerManager在source/server/server.cc的510行通過ListenerManagerImpl類的構造函數被建立,該構造函數傳入了4個參數:

第一個參數this,是這裡的server對象;第二個參數listener_component_factory_是監聽器元件工廠類ProdListenerComponentFactory,它将建立真實的套接字,在系統熱啟動時它會嘗試從父程序擷取套接字;第三個參數worker_factory_是一個工作線程工廠類ProdWorkerFactory,它将用于為伺服器建立工作線程;第四個參數是個布爾類型,訓示是否啟用事件分發器的統計功能,這個值預設是false,因為啟用了事件分發器的統計功能後資料量可能會非常大,如果需要啟用該統計功能,需要将bootstrap的enable_dispatcher_stats的值配置為true。下面我們來看ListenerManagerImpl類構造函數的代碼:

envoy/source/server/listener_manager_impl.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-6

261行:server.options().concurrency() 是指令行指定的工作線程的個數,預設是一個

262行:建立工作線程,這裡的worker_factory就是上文中提到的工作線程工廠類ProdWorkerFactory,其建立線程的額函數createWorker()如下所示:

envoy/source/server/worker_impl.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-7

建立ClusterManager

圖2-5中,server建立了ClusterManager,config_是一個Configuration::MainImpl對象,其initialize方法實作如下:

source/server/configuration_impl.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖2-8

94行:通過bootstrap的中叢集的配置來建立叢集管理器。

96行:通過bootstrap的中配置的靜态資源來建立了一系列靜态的監聽器。

98~101行:将這裡建立的靜态監聽器加入到了前面已經建立好的監聽管理器ListenerManager中

到這裡,envoy伺服器就建立完成了。接下來就要啟動伺服器了

第三節 啟動server

圖1-1中255行代碼啟動了server。這裡最終調用的是Server::InstanceImpl對象的run()方法,run()代碼如下:

source/server/server.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

 圖3-1

run()通過調用Server::RunHelper來運作,Server::RunHelper隻有一個構造函數,這個構造函數在構造Server::RunHelper對象時啟動server,Server::RunHelper的關鍵代碼如下:

source/server/server.cc

envoy源碼分析(一):啟動第一節 main函數第二節 建立server第三節 啟動server

圖3-2

732行:這裡初始化了一個init_watcher_,這是一個Init::WatcherImpl對象,這個對象的構造函數有兩個參數,第一個參數是個字元串,是這個對象的名稱,第二個參數是個回調函數,當Init::WatcherImpl對象被初始化管理器InitManager調用時,會執行該回調函數,回調函數中執行的是post_init_cb回調函數,從圖3-1可知這裡的post_init_cb回調函數中執行了startWorkers()函數,前文中在建立ListenerManager時建立了建立工作線程,這裡startWorkers()函數就是将ListenerManager中的工作線程都啟動起來。

770行:這裡設定ClusterManager的初始化回調函數,當ClusterManager初始化成功後會調用該回調函數,該回調函數執行時,在786行InitManager會處理732行的init_watcher_對象,此時,post_init_cb函數會被執行,ListenerManager中的工作線程啟動起來了,到此,ClusterManager和ListenerManager都就緒了,整個envoy伺服器也就緒了。

Note:ClusterManager初始化包括靜态初始化和動态初始化,如圖2-5 ClusterManager的靜态初始化發生在建立server時,當運作server時,靜态的ClusterManager已經初始化成功,ListenerManager中工作線程會立即開始工作。CDs可以動态初始化ClusterManager,CDs相關的内容會在後續介紹

繼續閱讀