域名是一个有层次的结构,是一串用“.”分隔的多个单词,最右边被称为“顶级域名”,然后是“二级域名”,最左边的是主机名,层次关系向左依次降低。
比如极客时间的域名“time.geekbang.org”,这里“org”就是顶级域名,“geekbang”是二级域名,“time”则是主机名。使用这个域名,DNS会把 它转换成相应的IP地址,就可以访问极客时间的网站了。
域名不仅能够代替IP地址,还有很多其他用途。
在Apache、Nginx这样的Web服务器里,域名可以用来标识虚拟主机,决定由哪个虚拟主机来对外提供服务,比如在Nginx里就会使用“server_name”指令:
server {
listen 80; #监听80端口
server_name time.geekbang.org; #主机名是time.geekbang.org
...
}
域名本质上是个名字空间系统,使用多级域名就可以划分出不同国家、地区、组织、公司、部门,每个域名都是独一无二的,可以作为一种身份的标识。
举个例子,假设A公司里又个小明,B公司有个小强,于是他们可以分别说是“小明.A公司”,“小强.B公司”,即使B公司里也有个小明也不怕,可以标记为“小明.B公司”,很好的解决了重名问题。
因为这个特性,域名也被扩展到了其他应用领域,比如java的包机制就采用域名作为命名空间,只是使用了反序。如果极客时间要开发Java应用,那么它的包名就是“org.geekbang.time ”。
XML里使用URI作为名字空间,也是间接使用了域名。
域名的解析
就像IP地址必须要换成MAC地址才能访问主机一样,域名也必须要转换成IP地址,这个过程就是“域名解析”。
DNS现在已经成了互联网的重要基础设施,必须要保证域名解析稳定可靠,快速高效。
DNS的核心系统是一个三层的树状、分布式的服务,基本对应域名的结构:
1、根域名服务器(Root DNS Server):管理顶级域名服务器,返回“com”、“net”、“cn”等顶级域名服务器的IP地址; 2、顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如com顶级域名服务器可以返回apple.com域名服务器的IP地址; 3、权威域名(Authoritaative DNS Server):管理自己域名下主机的IP地址,比如apple.com权威域名服务器可以返回www.apple.com 的IP地址。
在这里根域名服务器是关键,必须是众所周知的,否则下面的各级服务器就无从谈起了。 目前全世界共有13组根域名服务器,又有数百台镜像,保证一定能够被访问到。
有了这个系统之后,任何一个域名都可以在这个树形结构里从顶至下进行查询,就像是把域名从右到左顺序走了一遍,最终就获得了域名对应的IP。
例如,要访问“www.apple.com”, 就要进行下面的三次查询:
1、访问根域名服务器,它会告诉你“com”顶级域名服务器的地址; 2、访问“com”顶级域名服务器,它再告诉你“apple.com"域名服务器的地址; 3、最后访问“apple.com”域名服务器,就得到了“www.apple.com” 的地址。
虽然核心的DNS系统遍布全球,服务能力很强也很稳定,但如果全世界的网民都往这个系统里挤,即使不挤瘫痪了,访问速度也会很慢。
所以在核心DNS系统之外,还有两种手段用来减轻域名解析的压力,并且能够更快的获取结果,基本思路就是”缓存“。
首先,许多大公司、网络运行商都会建立自己的DNS服务器,作为用户DNS查询的代理,代替用户访问核心DNS系统。这些“野生”服务器被称为“非权威域名服务器”,可以缓存之前的查询结果,如果已经有了记录,就无需再向根服务器发起查询,直接返回对应的IP地址。
这些DNS服务器的数量要比核心系统的服务器多很多,而且大多部署在离用户很近的地方。 比较知名的DNS有Google的“8.8.8.8”,Microsoft的“4.2.2.1”,还有CloudFlare的“1.1.1.1”等等。
其次,操作系统里也会对DNS解析结果做缓存,如果你之前访问过“www.apple.com” ,那么下一次在浏览器里再输入这个网址的时候就不会再跑到DNS那里去访问了,直接在操作系统里就可以拿到IP地址。
另外,操作系统里还有一个特殊的“主机映射”文件,通常是一个可编辑的文本,在linux里是“\etc\hosts”,在windows里是“C:\WINDOWS\system32\drivers\etc\hosts”,如果操作系统在缓存里找不到DNS记录,就会找这个文件。
有了上面的“野生”DNS服务器、操作系统缓存和hosts文件后,很多域名解析的工作就都不用“跋山涉水”了,直接在本地或者本机就能解决,不仅方便了用户,也减轻了各级DNS服务器的压力,效率就大大提升了。
下面这张图比较完整的表示了现在的DNS架构:
在Nginx里有这么一条配置指令“resolver”,它就是用来配置DNS服务器的,如果没有它,那么Nginx就无法查询域名对应的IP,也就无法反向代理到外部的网站。
resolver 8.8.8.8 valid=30s; #指定Google的DNS,缓存30秒
域名的新玩法
有了域名,又有了可以稳定工作的解析系统,于是我们就可以实现比IP地址更多的“新玩法”。
第一种,也就是最简单的,“重定向”。因为域名代替了IP地址,所以可以让对外服务的域名不变,而主机的IP地址任意变动。当主机有情况需要下线、迁移时,可以更改DNS记录,让域名指向其他的机器。
比如,你有一台“buy.tv”de 服务器要临时停机维护,那你就可以通知DNS服务器:“我这个buy.tv”域名的地址变了,原先是1.2.3.4,现在是5.6.7.8;于是DNS就修改内部的IP地址映射关系,之后再有访问buy.tv的请求就不走1.2.3.4这台主机,改由5.6.7.8来处理,这样就可以保证业务服务不中断。
第二种,因为域名是一个名字空间,所以可以使用bind9等开源软件搭建一个在内部使用的DNS,作为名字服务器。这样我们开发的各种内部服务就都用域名来标记,比如数据库服务都用域名“mysql.inner.app”,商品服务都用“goods.inner.app”,发起网络通信时也就不必再使用写死的IP地址了,可以直接用域名,而且这种方式也兼具了第一种“玩法”的优势。
第三种“玩法”包含了前两种,也就是基于域名实现的负载均衡。
第一种方式,因为域名解析可以返回多个IP地址,所以一个域名可以对应多台主机,客户端收到多个IP地址后,就可以自己使用轮训算法依次向服务器发起请求,实现负载均衡。
第二种方式,域名解析可以配置内部的策略,返回离客户端最近的主机,或者返回当前服务质量最好的主机,这样在DNS端把请求分发到不同的服务器,实现负载均衡。
还有一些不怀好意的DNS,也可以在域名方面做手脚,比如:
“域名屏蔽”,对域名直接不解析,返回错误,让你无法拿到IP地址,也就无法访问网站。 “域名劫持”,也叫“域名污染”,你要访问A网站,但DNS给了B网站。