TrafficServer原始碼初體驗–2
剛剛在開篇中介紹到eventProcessor.start方法,這時trafficserver的事件處理子系統已經被啟動。接下來的程式碼分析過程種可以看到,這個事件處理子系統會被其他子系統使用。先把開篇種proxy/Main.cc的總控制流圖引過來,便於繼續分析。
eventProcessor之後,下面的程式碼
int use_separate_thread = 0; int num_remap_threads = 1; TS_ReadConfigInteger(use_separate_thread, "proxy.config.remap.use_remap_processor"); TS_ReadConfigInteger(num_remap_threads, "proxy.config.remap.num_remap_threads"); if (use_separate_thread && num_remap_threads < 1) num_remap_threads = 1; if (use_separate_thread) { Note("using the new remap processor system with %d threads", num_remap_threads); remapProcessor.setUseSeparateThread(); } remapProcessor.start(num_remap_threads);
這段程式碼是根據配置檔案,來選擇是否為remap型別的事件單獨啟動執行緒作為事件處理。如果需要,則會呼叫eventProcessor中的 ET_REMAP = eventProcessor.spawn_event_threads(num_threads, “ET_REMAP”);
接下來的
RecProcessStart呼叫沒怎麼看明白,從命名上感覺像是一系列的同步相關的排程,包括stat統計同步功能、conf配置同步功能、以及遠端同步功能,暫時不知做什麼的,細節等回過頭來在仔細研究吧。
然後 init_signals2 呼叫,根據我的理解應該是定期的將記憶體中的資料dump到stderr輸出中,用於日誌跟蹤。
接下來的這段程式碼用於處理命令列風格的啟動,如
traffic_server -C list 用於現實cache的配置情況。注意,這裡的cmd_mode是處理traffic_server的命令模式的命令,而不是traffic_server的啟動引數,換句話說,就是處理traffic_server -C (或者traffic_server –command) 這個模式的命令,包含(list,clear_cache,clear_hostdb,help)等。可以通過traffic_server -C help 看到命令模式支援的命令列表。
if (command_flag) { // pmgmt initialization moved up, needed by RecProcessInit //pmgmt->start(); int cmd_ret = cmd_mode(); if (cmd_ret != CMD_IN_PROGRESS) { if (cmd_ret >= 0) _exit(0); // everything is OK else _exit(1); // in error } }
接下來如果沒有定義過INK_NO_ACL(雙重否定,換句話說就是如果需要ACL控制) 則需要呼叫
initCacheControl() ,這個呼叫讀取 proxy.config.cache.control.filename 這個路徑對應的配置檔案,載入關於cache方面的訪問控制配置。
接下來
initCongestionControl(); IpAllow::InitInstance(); ParentConfig::startup(); #ifdef SPLIT_DNS SplitDNSConfig::startup(); #endif
分別是關於擁塞控制配置、ip allow,以及dns配置的處理。其中ParentConfig::startup()的作用暫時還沒搞得很明白。
接下來的 netProcessor.start();這行呼叫,真正開啟了網路事件的處理,包括epoll_wait的loop,是通過eventProcessor實現的event loop.
接下來進行的程式碼段如下:
#ifndef INK_NO_HOSTDB dnsProcessor.start(); if (hostDBProcessor.start() < 0) SignalWarning(MGMT_SIGNAL_SYSTEM_ERROR, "bad hostdb or storage configuration, hostdb disabled"); #endif
這段程式碼啟動dns事件處理以及hostDB事件處理,hostDB應該是負責cache的儲存。
隨後:
#ifndef INK_NO_CLUSTER clusterProcessor.init(); #endif
啟動cluster相關事件處理。
接下來的程式碼是載入http服務相關配置。
// Load HTTP port data. getNumSSLThreads depends on this. if (!HttpProxyPort::loadValue(http_accept_port_descriptor)) HttpProxyPort::loadConfig(); HttpProxyPort::loadDefaultIfEmpty();
接著啟動cache,udpNet,sslNetProcessor對應的事件處理。
cacheProcessor.start();
udpNet.start(num_of_udp_threads); // XXX : broken for __WIN32
sslNetProcessor.start(getNumSSLThreads());
貌似udpNet那塊並沒有使用epoll等高效的處理非同步非阻塞處理方式,具體原因還沒有分析。
然後啟動 日誌處理, Log::init(remote_management_flag ? 0 : Log::NO_REMOTE_MANAGEMENT);
擴充套件處理,處理擴充套件邏輯.(extension,而不是plugin,後面還會有一次對plugin的初始化)
plugin_init(system_config_directory, true); // extensions.config
start_stats_snap();啟動統計快照
body_factory = NEW(new HttpBodyFactory);
eventProcessor.schedule_every(NEW(new ShowStats), HRTIME_SECONDS(show_statistics), ET_CALL); 顯示當前統計資訊
接下來初始化外掛、啟動transformProcessor。transformProcessor應該是將使用者訪問的內容從源站取到ts上後進行一系列的轉換,用於最終傳回給請求呼叫者。
#ifndef TS_NO_API plugin_init(system_config_directory, false); // plugin.config #else api_init(); // we still need to initialize some of the data structure other module needs. extern void init_inkapi_stat_system(); init_inkapi_stat_system(); // i.e. http_global_hooks #endif #ifndef TS_NO_TRANSFORM transformProcessor.start(); #endif
接下來準備啟動http的proxy server,也就是我們看到的預設8080的埠將被開啟,ts將接受使用者請求,實現cdn服務。
init_HttpProxyServer(); int http_enabled = 1; TS_ReadConfigInteger(http_enabled, "proxy.config.http.enabled"); if (http_enabled) { #ifndef INK_NO_ICP int icp_enabled = 0; TS_ReadConfigInteger(icp_enabled, "proxy.config.icp.enabled"); #endif start_HttpProxyServer(num_accept_threads); #ifndef INK_NO_ICP if (icp_enabled) icpProcessor.start(); #endif } // "Task" processor, possibly with its own set of task threads tasksProcessor.start(num_task_threads); int back_door_port = NO_FD; TS_ReadConfigInteger(back_door_port, "proxy.config.process_manager.mgmt_port"); if (back_door_port != NO_FD) start_HttpProxyServerBackDoor(back_door_port, num_accept_threads > 0 ? 1 : 0); // One accept thread is enough
上面程式碼提到的icpProcessor是用於處理ICP協議( Internet Cache Protocol)的處理執行緒。taskProcessor是用於處理任務。
隨後啟動管理埠,可用於http web ui的管理
int back_door_port = NO_FD; TS_ReadConfigInteger(back_door_port, "proxy.config.process_manager.mgmt_port"); if (back_door_port != NO_FD) start_HttpProxyServerBackDoor(back_door_port, num_accept_threads > 0 ? 1 : 0); // One accept thread is enough
接下來啟動socks代理
#ifndef INK_NO_SOCKS if (netProcessor.socks_conf_stuff->accept_enabled) { start_SocksProxy(netProcessor.socks_conf_stuff->accept_port); } #endif
updateManager.start();
用於啟動自動更新ts配置。
run_AutoStop();
用於自動停止ts,停止後會有processmanager重啟,這個機制只在系統存在環境變數PROXY_AUTO_EXIT大於0的時候生效,並且程序會在PROXY_AUTO_EXIT秒後自動退出,然後由processmanager重啟這個程序。有點類似apache裡面的maxchildrequest那個玩意兒,到一定程度後,程序自動退出,隨後由監控程序重啟,這樣可以避免由於程式疏忽造成的記憶體洩漏問題。
最後啟動主執行緒。
this_thread()->execute();
到此為止,proxy/Main.cc的內容已經粗略的過了一遍,接下來準備對比較重要的部分深入探討下。