track服务优化

track服务优化之一 : DNS和域名

在互联网广告公司里,有一些服务是用作跟踪用户的,而这些代码嵌入的不多,qps也不高,然后文件大小也比较小,对于这样的应用我们如何进行优化呢。

我们http请求第一步开始说起。

大部分的http请求都是通过dns来进行的,这样dns解析的速度也关系到整个访问的速度。 下图中我们可以很明显的看到,这个请求最大的2个部分就是dns和内容下载。

14142519581_cde92247c1_z.jpg

我们知道DNS的缓存时间都由DNS设置TTL时间来决定的(除了部分local dns做强制缓存),而当一个域名在local dns中没有缓存时,local dns就会以迭代的方式去查询这个域名的解析。比如我们通过trace来模拟一个本地没有缓存的迭代过程。

下面是我们解析www.sohu.com的一个例子。 我们可以看到这里,首先是找到根域名的服务器,然后找到所有.com域名的根服务器,然后找到sohu.com域名的根服务器,然后解析了www.sohu.com, 而由于www.sohu.com做了一次cname,所以要进行解析,最终得到对应的IP地址。

而这个过程中,我们发现实际去dns.sohu.com的时间才52ms,而他去到根域名服务器和.com根域的解析时间加起来要452ms,而这个时间都是算在整个请求的时间内的。

14142949292_3223302e28_z.jpg

从上可以看到加快DNS解析速度的重要性,而在local dns中缓存是重重之重。而这个第一步就是统一域名,发现国内某些广告商居然用好多域名来进行跟踪。而google却只用了一个单独域名来进行。

下图是我直接访问这家广告公司的跟踪域名,可以看到光dns解析的时间就903ms,这个还是他们使用了dnspod的服务器的情况下。
14142949232_ddcb4b2a20_c.jpg

而他们的很多广告都使用了不同的域名,不过经过查询是应该用了泛域名解析。但是实际dns请求的时候还是会有延迟啊,local dns可不管是不是泛域名呢。 而这家广告商的这些域名指向最终都是同一个IP,那为什么不用单个域名呢?
14165904063_24dcd230ba_z.jpg

而我们看google ga,所有的ga使用的域名都是同一个。这样从dns层面减少了响应的时间。
14142519561_8ec892a088_c.jpg

从上面我们得到,使用单一域名在dns层面的好处是比较大的。

加快DNS解析速度的另外一个因素就是TTL时间。这个从解析速度来看自然是越大越好,比如很多根域名服务器都是缓存1周的,但是我们看到大量的还是缓存1个小时的。毕竟时间放太长,一旦网络出了问题都没办法切换。所以有些请求量很大的域名的ttl时间都是120秒左右的,就是怕万一有问题来不及切换。

这个就没有绝对的要求,全看各自的dns服务器的分布和性能了。


各种域名跳转方式

一个是使用bind的view功能。
这个首先就需要定义一个ACL列表,然后在name.conf中include一下就可以了。Acl定义的格式如下:

acl "company"{
1.1.1.1/32;
2.2.2.2/32;
};

每行定义记得用分号结尾就行。

下面这个是named.conf的配置。View也就是这里进行配置完成的。记得所有的zone必须在view中。

options {
directory "/usr/local/bind/var";
};
include "/usr/local/bind/var/company_acl.conf";
view "view_company"{
match-clients { company; };
#这里的company就是你前面acl中定义的acl名字

zone "abc.com" {
       type master;
       file "abc.com.company";
       allow-update { none; };
};
zone "." in {
       type hint;
       file "named.root";
};
zone "0.0.127.in-addr.arpa" in {
       type master;
       file "empty";
};
};

view "view_any"{
match-clients { any; };
zone "abc.com" {
       type master;
       file "abc.com.ns";
       allow-update { none; };
};
zone "." in {
       type hint;
       file "named.root";
};
zone "0.0.127.in-addr.arpa" in {
       type master;
       file "empty";
};
};

这些定义完成之后就是添加zone记录了。
下面这个是view_company的实例,其他类似就成。

$TTL 3h
@ IN SOA abc.com. ns.abc.com. (
 2009071601; serial
 3h  ; Refresh after 3hours
 1h  ; Retry after 1 hour
 1w  ; Expire fter 1 week
 1h )  ; Negative caching TTL of 1 hour
;
;name server
 IN NS ns.abc.com.
;
;address
;address
@  in mx 30   mail
abc.com. IN MX 10 mail.abc.com.
mail IN A 10.2.9.98
ns IN A 10.2.9.99
* IN CNAME update.microsoft.com.

总结一下,使用view功能就很容易可以把自己访问和其他访问进行区分对待,这个CDN的原理的一部分就是这样的。但是由于DNS本身是需要所有DNS来进行学习的。所以每次生效和失效当中的间隔比较长,如果只是短期更改,那最好不要使用DNS来进行。

第二种方式是用IPTABLES的转发功能来进行。
这里我们假设有2台机器。10.2.9.118是我本机。这个IPTABLES是设置在10.2.9.33上,10.2.9.99是被转发的机器,也就是除了我10.2.9.118能够正常访问10.2.9.33,其他人的访问都转发到10.2.9.99:80上。这里主要用到iptables得nat功能和filter功能。在redhat中就是替换/etc/sysconfig/iptables的内容。

# Firewall configuration written by system-config-securitylevel
*nat
:--PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:--POSTROUTING ACCEPT [0:0]
#上面3行都没有--这个符号,这里没办法才加的
-A PREROUTING -s ! 10.2.9.118 -p tcp --dport 80 -j DNAT --to-destination 10.2.9.99:80
#这个表示除了10.2.9.118来的访问10.2.9.33的80端口全部转发到10.2.9.99:80上
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:RH-Firewall-1-INPUT - [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -i eth1 -j ACCEPT
-A FORWARD -i eth0 -p tcp --dport 80 -d 10.2.9.99 -j ACCEPT
#这个表示允许10.2.9.33可以转发到10.2.9.99上。
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
#上面2个表示开通本机的22和80端口允许任何人访问
COMMIT

上面修改完成后海不能算最后生效,还需要打开10.2.9.33的ip转发功能。修改

/etc/sysctl.conf 中net.ipv4.ip_forward = 1 

默认这个值为0,表示禁止转发,改成1就行,然后执行

sysctl –p /etc/sysctl.conf

就行了。
最后我们还要在10.2.9.99上建立一个默认网站。因为iptables中转发过来的是ip+端口的形式。所以必须让10.2.9.99有默认网站。这个默认网站上。在nginx中,在配置文件最上面的网站就是默认网站。

    server {
        listen       80;
        server_name  update.abc.com;

        location / {
            root   /opt/update/;
            expires      180d;
            index  index.html index.htm;
            access_log  logs/defalut.access.log  main;
        }
        error_page   500 502 503 504  /index.htm;
        error_page   404          /index.htm;
        location = /index.htm {
            root   /opt/update/;
        }
        }

这里设置了所有的404和500错误全部被转向到index.htm上了。当然你可以使用rewrite来完成这样的功能。这样无论用户访问10.2.9.33上的任何网站都会被转到10.2.9.99的默认网站,除了我自己以外,哈哈!

最后一种重定向方式就是使用nginx的geo模块。这个在以前的日志已经有写,可以参考https://zauc.wordpress.com/2008/11/22/nginx-ge/