DNS(Domain Name Service)的起源:

    在互联网早期,计算机很少的时候,人们使用ip进行标识另外一台主机,从而与之通信,然而当计算机数目越来越多的时候,人们发现利用ip进行标识主机越来越力不从心。于是人们使用一些字符来标识主机,因为我们人类对一些比较有意义的文字记忆(如www.baidu.com)比记忆那些毫无头绪的号码(如219.125.233.35)往往容易得多,但是tcp/ip协议并不能使用这些字符作为目标主机进行通信,所以还需要将这些字符转换成对应的ip。为了规范这些字符,人们给它制定了一个格式fqdn(个人理解,百科上的fqdn不好理解)。将fqdn转换为ip的过程或者相反就是dns的功能。

FQDN(Full Qualified Domain Name):完全合格域名,其实就是一个主机名,类似于:www.baidu.com. 注意:最后面那个.是必须的,这样才是合格域名,.代表根域的意思


1.主机名和域名的区别:

    主机名是一台具体的主机名字,而域名是范围的概念,就比如说www.baidu.com.,这个一般情况下是一台具体的主机,www是主机名,被baidu.com. 这个域管辖,而baidu.com.又被com.域管辖,com.又被.这个根域管辖,.根域是最高级别的域,所有的域名都在它的范围内。 但是,如果www.baidu.com.被定义为一个域的概念,此时,它就是一个域名,此时它可以管理其他主机,比如www.www.baidu.com.等


2.名称解析框架nsswitch:

    我们有很多情况下需要进行名称转换,比如登陆系统时,用户名需要转换用户id,各种服务和默认监听的端口之间也需要转换,FQDN需要转换为ip等等,这些功能它们都具有从一个名称转化到另外一个名称的特点,为此人们把实现这种共同特点的功能做成一个框架nsswitch,把它们的不同点做成各种库(libnss_files.so、libnss_dns.so)等,nsswitch本身并不提供具体实现,它只是提供一个平台,具体实现就靠这些库,它们的关系就类似于淘宝和淘宝卖家的关系,淘宝提供平台,不同的卖家利用这个平台卖不同的东西。



DNS的发展:从host到分布式数据库

1.简单host阶段

    我们知道,我们要进行FQDN-->IP之间的转换,除了需要stub resolver解析发起者、nsswitch框架和libnss_dns.so库文件外,我们还需要有个地方可以存储FQDN和IP之间的转换关系,一般我们把这种地方叫做数据库,最开始的时候,主机数量不多,人们把这些信息存放在hosts文件中。一条host记录格式如下:

    127.0.0.1   localhost.localdomain localhost

    第一部分为ip,第二部分为fqdn,第三部分为alias主机别名

    人们把网络内的所有主机名和ip的对应关系都记录到这个文件里面,以后访问主机的时候,stub resolver就通过nsswitch调用libnss_file.so直接查看这个文件进行转换,从而开始正常通信。


2.copy host阶段

    第一阶段有个问题,每次我们在网络中添加主机的时候,每台主机的host文件都必须更新才能跟新的主机利用FQDN进行通信。当网络改动不多的时候,这种改变尚可忍受,但是当改动频繁的时候,这个时候就不能忍了。于是,人们找一台服务器做成ftp或者其他共享文件的形式,以后更新host信息就只在这台host进行更新,每个节点定时从这台服务器copy host到本机覆盖原有的host,这样,成功地把客户端的改变转移到服务端,从而大大提高了效率。


3.分布式数据库阶段

    第二阶段的做法看起来已经大大地解决了问题了,但是人们没想到互联网急速发展,规模越来越大,所以需要记录的信息也越来越多,host阶段的方法已经不适合在这种场景中使用。假设现有1千万条记录就好,每次查询运气好就查询一次,运气不好就得遍历所有的记录,这对硬件资源和算法得要求就不是一般的人能接受的。于是人们发明了分布式数据库的做法:

    (1).把整个dns数据库划分成不同的区域

    (2).每个区域可以再划分并授权自己的子区域

    (3).每个区域仅仅拥有自己直接相邻的下级区域的数据信息和根域的位置(类似于我的附庸的附庸不是我的附庸)

    举个例子:(图片来自:http://blog.csdn.net/yipiankongbai/article/details/25031461)

wKiom1guurfh4IueAABNTAGgg68191.png-wh_50

    mail.cctv.com.这个主机名,归属于cctv.com.这个域名,而cctv.com.这个域名又归com.这个域名管,com.又归属于.这个根域管。所以我们要查找mai.cctv.com这个域名,我们就必须知道cctv.com的位置,要知道cctv.com就必须知道com的位置,要知道com的位置就必须知道.的位置,而.的位置是大家都知道的,上述(3)。

    但是.不知道cctv.com的位置,它只能知道com的位置,这样,每个分布式数据库的节点需要保存的信息只有自己节点和根的位置,信息量大大减少。

    一般地,我们根据节点的包含关系,从小到大编写域名地址,并用.隔开,格式如下:

    主机名.xxx.(xxx...).二级域名.顶级域名.      (xxx...代表中间可以出现多次)

    这也是一个完整FQDN的格式,因为书写习惯我们经常忽略最后的.,但是你会发现我们仍然可以访问,这是因为我们的程序自动帮我们补齐了这个.


域名的按级分类(叫法):

    (1)根域.

    (2)顶级域名(com、org、cn等)

        国家顶级域:cn(中国)、us(美国)等

        通用顶级域:常见7个:com(公司企业),net(网络服务机构),org(非营利组织),int(国际组织),gov(美国的政府部门),mil(美国的军事部门)

        基础结构域名(infrastructure domain):这种顶级域名只有一个,即arpa,用于反向域名解析,因此称为反向域名

    (3)二级域名

    (4)三级域名

    (5)...


1.那么,当使用分布式数据库后,dns又是怎么实现名称解析的呢?假设我们是mail.tsinghua.edu.cn解析mail.cctv.com,它是这样子的:

    (1).stub resolver出于以前的习惯,仍然会先去检查hosts文件里面是否有内容(linux下,这个可以在/etc/nsswitch.conf里面找到这个配置 :  (  hosts:      files dns )    这个配置告诉stub resolver先去检查hosts文件,我们也可以把files去掉,直接进行dns解析)。

    (2).如果hosts里面找不到相关信息,那么stub resolver就到指定的dns服务器上去找(linux下,在/etc/resolv.conf里面指定,这里我们假设mail是我们自己的主机名,我们指定tsinghua dns服务器,下面简称tsinghua服务器)

    (3).Tsinghua服务器收到这个请求后,就会查找自己的域名数据库里面是否有mail.cctv.com的对应内容,如果有,则返回,否则转交请求给根域

    (4).根域收到这个请求后,发现自己的dns数据库里面没有mail.cctv.com这个条目的内容,但是自己拥有com这个域的信息,于是,它可以有以下两种做法:

        <1>根域自己向com发起请求,com发现自己也没有mail.cctv.com的信息,但是有cctv.com这个域的信息,于是com向cctv.com 发起请求,cctv.com发现自己有mail.cctv.com的信息,于是把解析结果告诉com,com收到结果后告诉., .再告诉tsinghua,tsinghua再响应给本地的mail。 这种客户端只需发起一次请求,各个节点互相转发的过程,我们称之为 递归。

        <2>根域并不直接向com请求,而是告诉Tsinghua服务器:我这没有,但是你可以找com,com的位置是xxx。  于是Tsinghua自己向com请求,com没有,也告诉Tsinghua  cctv.com的位置,然后tsinghua自己向cctv.com进行请求,最终得到最后的结果。这种客户端多次请求的过程,我们称之为迭代。

        实际上,如果根给每个人递归,那么根自己会忙死,所以出于安全和效率等方面考虑,根不给任何人递归,而且我们发现我们真正的客户端mail,实际只请求了一次,而tsinghua dns服务器则迭代了多次。所以现实中,一次dns解析,一般是一次递归多次迭代的结果


2.假设这么一种场景:tsinghua下的mail对mail.cctv.com进行请求,Tsinghua辛辛苦苦地迭代多次找来了解析结果,此时,如果Tsinghua下的www也向mail.cctv.com发起请求,我们有没有必要再迭代一次呢?

    答案显然是没有必要的,因为迭代一两次还好,如果Tsinghua下的主机频繁地访问相同的fqdn,那么Tsinghua的很多时间将会浪费在无意义的重复动作上。所以每台主机解析完dns后,都会缓存一份,下次请求的时候就不必再向dns请求。但是这份结果只能主机独享,所以它们所属的dns服务器也要有自己的缓存,这样,当访问相同的主机的时候,dns服务器直接从缓存中解析,大大提高了效率。


3.dns服务器缓存带来的问题:

    (1)我们知道我们的解析不是一成不变的,所以我们有可能改解析(主机故障、环境迁移等因素),所以我们缓存不能永久缓存下去,必须要有个过期时间以方便我们更改。但是这个过期时间又如何确定呢?想想看谁最有权威设定这个时间? 答案就是:主机名所属的上一级域名dns服务器,比如说www.baidu.com,那么知道这个域名最近更新动态的就应该是baidu.com(因为www.baidu.com归baidu.com这个域管)。所以,我们请求域名解析的时候,它会附属返回个过期时间。dns服务器根据这个时间缓存,超过这个时间则再次迭代。

    (2)即使有缓存时间,我们也会有解析已经更新而缓存时间未到的情况,此时我们返回的结果是不准确的。根据这个特点,我们把dns服务器的返回结果分成权威答案和非权威答案两种:

        权威答案:由域名所被管辖的上级域名服务器返回的结果,比如www.baidu.com,由baidu.com这个域名的dns服务器返回的结果就是权威的

        非权威答案:任何不是由域名所被管辖的上级域名服务器返回的结果都是非权威答案(因为这些都是缓存的结果,存在过期时间未到解析却更新了的情况)

    (3)假设我们一直访问一个不存在的域名,比如baidu.com下没有hhh.baidu.com,那么返回的结果是否也要返回过期时间呢?  答案是肯定的,这是为了防止有人恶意访问,对dns进行攻击。


4.我们刚才都讨论的客户端通过自己dns服务器请求别的域的dns的情况,事实上,它还可能面临以下两种场景:

    (1)客户端向dns服务器请求解析dns服务器域内的其他主机(比如www.baidu.com请求解析ftp.baidu.com)

这种情况没什么好说的,有就返回解析结果,没有就返回没有信息

    (2)别的客户端通过别人的dns服务器请求解析别人的dns(比如www.baidu.com通过sina.com的dns服务器解析www.edu.com)

这种要看对应dns服务器的设置,一般是不允许给别人递归的,但也有一些类似于8.8.8.8和114.114.114.114的公共dns服务器愿意给别人递归查询


dns的实现:

    我们知道每个域都应该有自己域下的主机的信息,域本身只是一个概念,实现域的功能的其实是一个服务器。除了根域外,域本身归属于其他域管理,所以管理这个域的上级域必须知道这个域服务器的位置。(比如baidu.com,com必须知道管理baidu.com的这个域的主机名称和位置)一般我们把这个域服务器叫做ns,(比如baidu.com这个域的域名服务器一般是ns.baidu.com.,com的域名服务器一般叫ns.com , 久而久之,人们就把域名服务器成为ns服务器),ns服务器本身也需要解析,所以一般一个域的域名数据库的开头一般需要有类似这样的信息(拿baidu.com为例):

        baidu.com.       NS      ns.baidu.com.  (指定哪个主机实现管理域名服务器功能)

        ns.baidu.com    A        1.1.1.1    (这个主机在哪个位置)

  ns和A是记录的类型,至于它们是什么意思代表什么,如何实现dns服务,我们下篇再讲。