DNS模块学习
时间:2010-11-22 来源:wahu0315210
首先从配置管理上分析dns模块。以下给出ts配置文件records.config中与dns相关的配置选项:
CONFIG proxy.config.dns.splitDNS.enabled INT 0 |
dns针对以上两种解析方式,采用如下设计逻辑进行了实现:通过DNSProcessor+DNSHandler+DNSEntry实现dns解析;通过SplitDNS+SplitDNSConfig+SplitDNSRecord提供额外的splitdns解析功能。
(1)
dns解析遵循ts的异步事件模型的设计原理[3],DNSProcessor借助DNSHandler对一个域名进行解析。
DNSEntry类实现了对一个dns请求的封装。ts内部实现封装了一组与libresolv库相同功能的方法[4],例如ink_res_int等等。
DNSHandler维护了两个队列:
struct DNSHandler: public Continuation |
if (dns_ns_rr) {//使用roundrobin |
根据以上分析,通过DNSHandler::startEvent,与dns解析服务器进行连接。在startEvent函数中,通过下面两行代码异步周期调用DNSHandler::mainEvent:
SET_HANDLER(&DNSHandler::mainEvent);
dnsProcessor.thread->schedule_every(this, DNS_PERIOD); |
recv_dns(event, e); |
下面分析ts是如何将一个dns请求插入到DNSHandler维护的DNSEntry队列中去的。前面提到,dns解析遵循ts的异步事件模型的设计逻辑,这种设计逻辑通常由Processor调度Handler处理一个Continuation状态序列,在这里也不例外。DNSProcessor提供了一组get方法作域名解析,这些get方法都通过内部调用DNSProcessor::getby方法实现域名解析,以DNSProcessor::gethostbyname为例:
inline Action * |
DNSEntry *e = dnsEntryAllocator.alloc(); |
SET_HANDLER((DNSEntryHandler) & DNSEntry::mainEvent); |
dnsH->entries.enqueue(this); |
通过以上分析可以看出,dns解析通过DNSProcessor::getby不断处理每一个dns请求,并构造dns消息体插入到DNSHandler对应的DNSEntry队列中去,DNSHandler定期调用DNSHandler::mainEvent方法从dns服务器中取回dns响应,并根据其维护的DNSEntry队列构造新的dns请求发送给dns服务器。
dns解析是通过DNSProcessor::start方法启用的。该方法首先读取一些配置选项,然后执行DNSProcessor::dns_init加载resolv_conf变量对应的文件(默认为/etc/resolv.conf),最后执行DNSProcessor::open方法,该方法内部调用DNSHandler::startEvent,接下来按照上面描述的流程,一个dns解析服务就启用了。
(2)
splitdns是后来的ts开发团队在原有基础上增加的功能,设计逻辑非常混乱,以TrafficServer2.1.4版本为例,整个代码嵌套在了iocore/dns,iocore/hostdb,以及proxy模块中。从功能上来看,目前splitdns的功能还不是很完善,后续需要很多改进,[1]介绍了后续的一些改进方案。以下大体介绍一下splitdns相关的一些关键代码。
1)SplitDNSConfig通过SplitDNSConfig::startup方法根据配置文件选项选择是否启动splitdns功能,该函数调用SplitDNSConfig::reconfig函数。下面分析reconfig这个函数的内容:
IOCORE_ReadConfigInt32(gsplit_dns_enabled, "proxy.config.dns.splitDNS.enabled"); |
params->m_DNSSrvrTable = NEW(new DNS_table("proxy.config.dns.splitdns.filename", modulePrefix, &sdns_dest_tags)); |
typedef ControlMatcher<SplitDNSRecord, SplitDNSResult> DNS_table; |
函数体,里面有这么两行关键代码:
Data *cur_d; |
2)通过SplitDNSConfig::startup方法,当在records.config文件中enable splitdns后,splitdns已经开启。我们接着分析SplitDNSRecord这个结构体,可以看出其内部有一个成员:
DNSServer m_servers; |
struct DNSServer |
3)SplitDNS这个结构体提供了对外的接口。SplitDNS::getDNSRecord解析参数指向的域名,并返回一个DNSServer,从而也间接得到了一个DNSHandler。将这个DNSHandler作为参数调用DNSProcessor::getby,就可以实现从splitdns模块解析一个域名了。
从上面的描述中我们可以看出,通过splitdns解析一个域名。只需要首先配置records.config文件,将CONFIG proxy.config.dns.splitDNS.enabled赋值为1;然后通过
SplitDNSConfig::startup(); |
|
针对splitdns的功能完善问题,TS-435[5]以及TS-541[6]有更为详细的描述。
[1]https://cwiki.apache.org/confluence/display/TS/HostDBandDNS
[2]http://trafficserver.apache.org/docs/v2/admin/ConfigurationFiles下面splitdns.config
[3]http://trafficserver.apache.org/docs/v2/sdk/CreatingTSPlugins.htmlchapter2
[4]http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=/apis/resmkq.htm
[5]https://issues.apache.org/jira/browse/TS-435?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12932442#action_12932442
[6]https://issues.apache.org/jira/browse/TS-541