http://skysbird.bsdchina.org/?p=237
刚刚在开篇中介绍到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的内容已经粗略的过了一遍,接下来准备对比较重要的部分深入探讨下。