由于因特网的实现是一个分层架构,为了防止篇幅过大,笔者不想一篇文章就写完想表达的所有内容,于是会以系列文章的方式,主要内容包括TCP/IP分层架构、网络层的最短路径算法:Dijkstra算法的实现细节,传输层的TCP传输控制协议的拥塞控制、流量控制以及握手和挥手,和应用层的DNS服务。
《TCP/IP参考模型-分层架构》
《TCP/IP参考模型-应用层的DNS》
《TCP/IP参考模型-传输层TCP》
《TCP/IP参考模型-网络层Dijkstra算法》
Internet通过统一的IP地址来标识一个节点,而IP地址这种点分十进制对于人类来说,不太好记,而且节点的IP地址可能会经常变化(IPV4的紧缺性)。所以希望能给某个(或某集群)节点命名,并且希望能通过名字来访问节点。DNS的雏形是一个节点中的hosts.txt文件,这个文件记录了主机名字到IP地址的映射,大家都通过访问这个节点来找到对应主机的IP地址。但是正如大家看到的,网络内主机在数百台以内的时候还好处理,大家一起维护这个文件,但随着Internet的出现,网络内的主机数量呈指数增长,单个节点的负载,以及维护一致性就带来了重大的问题。
于是乎DNS(Domain Name System 域名系统),被发明了出来。它是一个庞大的、遍布全球的分布式数据库,域名的命名规则是分层次的,主要分为顶级域名和子域名,子域名里可以分很多级,但常用的也就到二级和三级。如果把它们之间的关系表示成树,那么每一级就代表着树的一层。example:www.google.com。
顶级域名可以区分为两个大类:国际通用顶级域名(.com、.org、.net等)和国家/地区顶级域名(.cn、.us、.jp等),顶级域名根据其用途又可以分成很多种,常见的几种在下表中给出:
顶级域名 |
用途 |
.com |
商业机构,任何人都可以注册 |
.edu |
教育机构 |
.gov |
政府部门 |
.int |
国际组织 |
.net |
网络组织,例如因特网服务商和维修商,现在任何人都可以注册 |
.org |
非盈利组织,任何人都可以注册 |
.info |
网络信息服务组织 |
一个可用的域名必须拥有两级,比如baidu.com。它需要在顶级域名授权机构里申请,当申请通过后,这个二级域名之后的三级、四级等等,归申请者所有。
域名系统最主要的作用就是通过名字查询IP地址,当一个客户机需要访问某个网站时,它知道该网站的域名,于是客户机会发起一个UDP请求给本地域名服务器,请求参数是域名,本地域名服务器返回IP地址给客户机,客户机再进行真正的请求,比如建立TCP连接。
为了避免前言中提到的单点故障、一致性问题,域名服务器采用一种分层、分域的,有数据冗余的数据库结构,大大提高了可靠性。
域名服务器主要分为以下几种:
服务器类别 |
用途简述 |
根域名服务器 |
告知顶级域名服务器的IP |
顶级域名服务器 |
告知权威域名服务器的IP |
权威域名服务器 |
告知子域指向的IP |
本地域名服务器 |
给客户端提供递归查询服务 |
其中根域名服务器在全球一共有13台,在下表中列出,本地域名服务器负责给客户查询IP地址,在没有缓存的情况下,它首先发起的请求就是给根域名服务器的。
名称 |
主服务器位置 |
IP |
A |
美国弗吉尼亚州 |
198.41.0.4 |
B |
美国加利弗尼亚州 |
128.9.0.107 |
C |
美国弗吉尼亚州 |
192.33.4.12 |
D |
美国马里兰州 |
128.8.10.90 |
E |
美国加利弗尼亚州 |
192.203.230.10 |
F |
美国加利弗尼亚州 |
192.5.5.241 |
G |
美国弗吉尼亚州 |
192.112.36.4 |
H |
美国马里兰州 |
128.63.2.53 |
I |
瑞典斯德哥尔摩 |
192.36.148.17 |
J |
美国弗吉尼亚州 |
192.58.128.30 |
K |
英国伦敦 |
192.0.14.129 |
L |
美国弗吉尼亚州 |
198.32.64.12 |
M |
日本东京 |
202.12.27.33 |
顶级域名服务器是那些拥有顶级域名的机构管理的,比如.com、.cn。它们会把自己的IP地址提交给根域名服务器,这样本地域名服务器就能通过访问根域名服务器得到众多顶级域名服务器的IP地址。
权威域名服务器是顶级域名下的子域拥有者管理的,像阿里云这样的第三方机构,人们可以在上面申请顶级域名下的子域名,比如bytedance.com。
本地域名服务器一般是ISP运营商提供的,客户机需要依靠它来进行完整的DNS解析。
为了让大家看清楚各种域名服务器的作用,我们用一个常规的域名解析过程来讲解。
假设我们要访问全球最大的同性交友网站:www.github.com,应用程序会先检测自己的缓存(如果有的话)中有没有该域名的IP地址,并且time_to_live有没有过期,ttl表示域名的有效时间,如果没过期,解析就结束了。
当应用程序没有该域名的IP地址时,它会调用操作系统函数来查询,操作系统同样也是查看域名解析记录是否存在缓存中,如果有就结束。
操作系统缓存还未命中,才会正式向本地域名服务器发起请求,本地域名服务器首先也是检查缓存,缓存不存在后再开始递归查询。
递归查询的查询步骤如下:
图1展示了一个客户端向本地域名服务器发起递归请求,本地域名服务器迭代请求的过程:
图1
图1中第1步和第8步客户机与本地域名服务器的请求响应叫做递归查询,第2至7步都是迭代查询,因为每次请求都只返回了部分结果,就像一个查询必须访问所有的元素才能确认最小值最大值一样。
递归查询跟迭代查询最大的不同是,它给最终用户提供了完整的结果,而迭代查询只返回部分结果。
在第8步的时候,本地域名服务器就会根据解析记录中的TTL值来决定缓存多久,当下次再有同一个域名的解析请求过来时,本地域名服务器可以直接从缓存中返回结果,这样不管是应用程序缓存、操作系统缓存还是本地域名服务器缓存,都能减少对所有域名服务器的压力,而且域名解析也不要求实时,只要达到最终一致性即可。从缓存中返回的结果也叫非权威响应。
域名资源记录是存在域名服务器中的记录,在域名解析过程中就会用到这个记录,比如类型为NS的记录会返回需要的域名服务器地址,下面列出了常用的类型:
A记录是最常用的,它被用来获取域名对应的IP地址,比如某权威域名服务器下的A记录可能是这样的:
类型 |
主机记录 |
记录值 |
TTL |
A |
www |
112.xx.xx.xx |
600S |
当本地域名服务器请求权威域名服务器www这个子域的IP时,就会得到112.xx.xx.xx。
像阿里云这种权威域名服务器,还提供负载均衡的功能,你可以设置两个A记录,指向不同的IP,权威域名服务器会随机一个给本地域名服务器,达到分流的作用,如果你需要的话,还可以设置权重。
DNS作为Internet中一项关键服务,管理它的服务商必须保证它的高可用性,因为它被很多组件依赖了起来,所以高可用性是它的首要目标。而一致性对它来说则没那么重要,只需要做到最终一致性即可。
DNS经常被作为DDOS攻击的目标,比如发送大量的请求让DNS服务挂掉,达到拒绝服务的目的,甚至还有伪造源IP让DNS不停地向受害者发送解析记录的借刀杀人攻击。