TrafficServer源码初体验–2

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的内容已经粗略的过了一遍,接下来准备对比较重要的部分深入探讨下。


你可能感兴趣的:(thread,server,cache,System,Descriptor,statistics)