简述
这是对萌新的科普内容,尝试通过一个故事的方式通俗地讲解清楚DNS的解析过程,有误的地方欢迎大家指正!
PS:纯文本,无图,当小说看就行。
内容包含:
- 域名的公网的解析流程
- 域名在主机内部的解析流程(下篇)
嫌长不看的同学就只用记住5个字就行了,“别问我,问他”,这就是DNS解析流程的核心。
开篇
小陈穿越到了平行时空A的20世纪60年代,地点是US,拥有着早期的第一批计算机,成为了一个程序员。
小白穿越到了平行时空B的20世纪60年代,地点是CN,啥也没有。
小陈:我的电脑应该如何与其它机器通信呢?
答:此时还没有网络,主机之间的通信只能用专用线缆,例如使用串口线一对一进行传输。
小白:我应该如何与其他人进行联系呢?
答:吼,走路串门,写信。
小陈:发现慢慢地大家拥有的计算机越来越多了,逐渐有了多机器通信的需求。怎么办呢?
答:略过多种方案的角逐,最终以太网方案胜出,大家进入到同一个互联网内开始了使用 IP 地址进行通信的年代。
小白:需要联系的人也慢慢多了起来,走路写信都很麻烦,该怎么办呢?
答:略过残酷的原始资本积累(真搬砖),有钱后安装了一个固定电话,想联系谁拨打对方的电话号码就能说上话。
小陈:所在的互联网内又有了更多机器,需要通信的主机ip太多记不住,交流每次都要配置一长串IP地址很麻烦怎么办呢?
答:给经常需要通信的机器的IP地址起个别名(昵称/外号)吧。别名和IP地址 存放在一个文件内(/etc/hosts),每次需要要输入IP时,先通过别名去文件内查询一下。
小白:需要联系的人也更多了,电话号码太多脑袋也记不住了。
答:用一个小本子做电话号码通讯录,每次要打谁的电话,先翻开一个本子找出电话号码来。
PS:以前没有手机的年代,很多人随身都带着一个记满号码的本子(包括我^_^)。
小陈:一段时间后,觉得每次都要去手动查询太麻烦,需要简化。
答:写了个程序方法(glibc 内的 getaddrinfo 和 gethostbyname),以后上层应用如果使用名字通信,可以先调用这个方法,自动去 hosts 文件内查询出真实的IP地址,再与真实IP进行通信。
小白:一段时间后,也觉得每次都要翻电话本太麻烦。需要简化。
答:买了个手机,保存通讯录到手机里面,后续直接输入人名然后点拨号即可,不需要再管号码了。
愉快的很多年过去啦。。。
小陈:发现了一个问题,本地开发的一个程序,拷贝到别的机器上去后执行出错了,解析出来IP地址不是预期的那个目标。
小白:我也发现了一个问题,有天手机没电,拿同事的手机输入“我老婆”,居然是个男人接听的,吓得给挂了,一直想不明白问题出在哪。
小陈:找到了问题原因了,大家的 hosts 文件内容有差异和冲突,一个别名在不同主机的文件里面映射成了不同的IP地址。
答:提出了个解决办法,以后我来维护一个统一的 hosts 文件, 做公益,免费为大家提供名字到IP地址的查询服务。大家主机上配置好我的服务器IP(做为DNS服务器),每次和谁通信前都请求一次我的服务解析出真实IP地址即可。
小白:也找到问题原因了,原来大家手机通讯录里面名字和号码都是不一样的。突发奇想,如何通过一个名字,在使用任何人的手机时也都能保证是打给同一个人的号码呢?
答:也有个解决办法,小白决定自己来维护一个公共电话通讯录和一个总台号码。大家每次打电话前先打给小白的总台号码,然后告诉小白一个名字,小白会告诉你对方正确的电话号码,大家再按小白告诉的这个号码打过去。
PS:类似于 144 提供的号码查询服务。
愉快的很多年又过去啦。。。
小陈:抗不住啦,随着名气的增加访问量越来越多,而且维护的条目数量也越来越多,我这台电脑无论是网络带宽,还是CPU和磁盘容量都支持不住啦!
答:最简单的解决办法,扩容,两台服务器,再不够后就四台。并且公开一个我的服务器清单(named.root)给大家,大家每次从这个清单里面任选一个我的主机进行查询解析。
小白:接电话接到吐,太累了。
答:发动老婆孩子齐上阵,告诉大家总机不只有一个,一共有三个,大家随便选一个打就行。
小陈:又抗不住了,已经扩容到13台了(13台DNS根域服务器),我一个做公益的,不能这样无限制投入。
答:发动各个组织或国家起来负责,以后你本组织的或本国出一台服务器来给大家提供查询服务。我只负责告诉大家这个组织的IP是什么,关于这个组织内部的IP情况我都不管了。
于是小陈的13台服务器现在就不用存全球的名字和IP地址映射表了,只需要存几百个组织和国家的名字和IP,硬盘容量和IO性能这时基本上不用考虑了。\
PS:向小陈发起域名查询时,如果名字后面的标记归属于某组织,则小陈只会告诉你这个组织的IP地址,你去那里找它查询。
小白:我要吐槽,人手不够先不说,通讯录厚比天高也先不说。免费给大家提供号码查询服务,反映慢了还被人喷没有服务意识,做好人难啊!
答:发动热心群众,例如选100个宗族大姓的负责人,以后关于这些姓氏的电话号码查询就去找他们姓氏的负责人问。不再回应具体人名的电话号码查询。
于是厚比天高的通讯录一下子缩减成了两三页纸,小白心里美滋滋。
PS:例如呼叫总台找张某某,小白就会直接告诉你,姓张的不归我管,我只能告诉你张老大的电话,你另外打他的电话去问。
小陈:已经有了各组织的独立域名服务器,为什么大家每次还来访问我的机器进行查询,访问量一点没少。
各主机:只有你有完整的组织IP地址表啊,不找你查找谁查,况且如果有组织更新,增加或减少了,我们都是不知道的啊,不还是得找你啊。
小陈:接受现实。
小白:已经有了各姓氏负责人的电话,为什么大家每次都还打我的电话进行查询,我想退出不想干了。
群众:别啊,只有你有完整的各宗族姓氏负责人的通信录,如果有负责人增加减少或者换号了,还是得问你啊。
小白:我忍。
小陈:访问量与日俱增,这样下去不是个办法,得想办法让访问量降低下来。
小陈:发现原因了:有个机器每天要来查同一个名字一万次,你就不知道本地记录一份吗?
各主机:要是这个名字对应的IP突然变了,你能主动同时通知我们?
小陈:我不能,面对全球这么多访问者,小陈的13台的主机显然是不能的。
小白:来打电话查询号码的数量越来越多,得想办法减少一些啊。
小白:发现原因了:李四每天给王五打80个电话,每次都来总台问号码,你就不知道存到自己手机上吗?
李四:万一他哪天突然换号码了没给我说怎么办,你主动告诉我?
小白:“我不能”,看着这满眼期待的几亿用户,小白并没有半秒迟疑。
小陈:还是得找个办法降低访问量。
答:域名和IP的的映射关系虽然是可能会变,但不是随时在变啊,更况且我所维护的这百来个组织的名单更不可能经常会变啊。于是做出了个办法:每次被查询时,除了响应域名所对应的IP地址,还另外附加一段内容告诉对方这次查询的结果,可能在未来的一段时间(TTL)都不会改变,建议对方在这段时间内不要再向我的主机进行这个域名的查询,除非期间访问对方的IP失败了,便可以再来查询。
小白:我也有个办法降低大家打我总台电话的次数。
答:人确实会换号码,但换的频率肯定不高,更何况那些姓氏负责人的电话几乎几年不换。于是在每个人来查询号码时,都附加一句,这个号码预计多久内不会变,这段时间能如果能打通就不要找我啦。如果打不通,或者打通了不是你要找的那个人,再来找我重新查。
小陈:既然我只负责各组织的服务器域名和IP映射表,而且它们也很难一年几次,那就设置它们的预期有效时间(TTL)为半个月吧。同时建议各组织的域名服务器将自己所负责的域名的预期有效时间(TTL)设置为7天,这样大家就都大大少压力了。
效果:小陈这的DNS查询量骤然下降100百倍,小陈心里美滋滋。
小白:那我就将我这维护的各姓氏负责人的电话预期有效时间设置为15天,并且建议各姓氏负责人将自己所负责的电话号码预期有效时间设置为7天。
效果:小白这里的电话号码查询量也骤然下降100百倍,小白心里也是美滋滋的。
愉快的很多年又又过去啦。。。
小陈:虽然大家都很长时间才来我这查一次,但架不住设备越来越多啊,访问量又涨起来了。
答:需要根本性解决这个问题,不能再面向全球所有普通设备开放服务了。于是想了两个办法:
-
告诉各地区的网络运营商,你们可以在当地设置一个DNS缓存服务器,缓存任何还在预期可用时间内的域名解析记录。
如果这个区域内的主机都将域名查询服务器地址指向它们,而缓存服务器使用有效的内部缓存记录直接进行响应。这样将大大减少查询时的耗时,也减少了比如国际宽带资源的占用。
但是如何让这些设备知道这个区域内的域名服务器的地址呢?就得靠第二个办法了。 -
联系各主机厂商和操作系统厂商,以后不要在新主机上内置我的13台根域名服务器清单了,改为动态获取这个区域内可直接响应最终结果的域名查询服务器。
(实际是在DHCP分配IP时一并分配的本区域DNS服务器地址)
效果:到根DNS服务器进行查询的访问量极大地减少了,现在只有每个区域的缓存服务器才会来访问查询了。
小白:虽然大家也是都很长时间才来我这查某个电话号码一次,但同样架不住人越来越多啊,访问量又涨起来了。
答:同样需要根本性解决这个问题,我也想了两个办法:
- 告诉各地区应该将当地那个唯一会英语的老师,且愿意记录大家号码的人的手机号码公布出来。
- 告诉大家我以后不接受中文的查询服务,只接受英文的查询服务。
效果:大家查询电话号码时,先去找那个英语老师,英语老师那里如果有有效的记录则直接响应,没有记录或者记录过期了,则由英语老师拨打小白的电话进行查询。于是小白这里的查询的量又骤然下降,小白再次喜笑颜开~
至此基本的DNS查询流程描述完毕。
小陈所在网络的主机需要查询一个域名所对应的IP地址时,如查询 abc.com
- 发送请求给本地DNS服务器
- 本地DNS服务器如果缓存内有就使用缓存的数据进行响应
- 缓存内没有,则本地DNS服务器向根域服务器进行查询
- 根域服务器告诉本地DNS服务器应该去 com 这个组织所负责的子域服务器进行查询, 这个组织的子域服务器IP是 XXX
- 本地DNS服务器再次向子域服务器进行查询,获取到真实的IP地址
- 响应给客户端主机
小白这边的电话号码查询流程也类似
- 李四打英语老师的电话,问王五的号码是什么
- 英语老师这里如果有有效的记录,则直接回复
- 英语老师这里没有,则打电话使用英语向小白进行查询
- 小白告诉英语老师,你找王氏负责人问吧,他的电话是XXXX
- 英语老师打电话问王氏负责人,王五的号码是什么,获得了真实的号码
- 英语老师回复给李四
衍生知识
如果子域服务器也抗不住了,就会参考根域名服务器的这个办法再设置一级孙域名。
例如 abc.def.com,根域始终是那13台,子域(顶级域)就是 com, 孙域(二级域)就是 def, 曾孙就是 abc, 一直可以无限衍生。
重点是除了最后一级,之前的每一级都不会正面回答IP是什么,而是告诉查询者应该去哪查。
一些域名服务器相关的角色
- 本地DNS服务器:一般来说就是接入运营商时自动获取的那个DNS服务器,或者是自己配置的第一个DNS服务器。
- DNS缓存服务器:一般来说本地DNS服务器就兼了这个角色,两者概念几乎一致。如果刻意并列来说,那就是指纯缓存,不转发这种。
- DNS转发服务器:原意是指只负责转发查询的服务器,但实际本地DNS服务器也兼了这个角色。
- DNS代理服务器:本地无缓存,纯TCP/UDP代理。
- DNS权威服务器:也就是指某个子域或孙域服务器,归属于这个域名下的名称的IP是谁它最有发言权。
- 根域名服务器:就是那13台全球根域名服务器。
- DNS客户端:只能向本地DNS服务器进行查询,不能访问别的节点,原因是它只能接受最终结果,而处理不了“问他”这个逻辑。
PS:终端电脑DHCP获取的那个DNS服务器地址(192.168.1.1),一般都不是本地DNS服务器,而是本地网关兼职的DNS代理服务。
如何更新域名的IP地址
要考虑到DNS缓存服务器会根据TTL时间进行的缓存。
-
保守做法:
先将原域名的TTL时间改短,例如由7天改为1个小时,正式操作前再改为1分钟或更短,改完再调长TTL的时间为7天,这样造成的解析到原IP的时间就最多1分钟了。 -
实际做法:
流量不大就直接修改,不用管TTL时间,全网很快就会都变了。 -
建议做法:
原IP地址在修改域名地址时依旧保留并提供服务,等一会儿没流量了再下线。
备注1:我之前做域名IP变更时,是直接修改的域名,没有管TTL。但内部设置了原IP地址服务入口到新IP地址服务入口的流量转发,据观察修改后绝大部分流量都立即迁移到了新IP地址上,原IP很快便没有了流量。
备注2: 我后来又做变更时发现,有些DNS服务商更新很块,有些则更新很慢;
比如我这个域名变更地址后, 通过阿里云DNS工具检测,全国很多节点都很快更新了(1分钟内就有更新了);
但是例如 8.8.8.8 114.114.114.114 这些大的DNS服务商确更新很慢,我等了20分钟都没有变过来。
所以最好在迁移时在入口IP层加一层转发逻辑。
实际上主机侧本地缓存的DNS时间很短,这个下篇来说。
衍生思考
问:为什么DNS解析流程最终会是这样的?
答:我认为一个很重要的原因,就是因为它是免费开放的。
假设它是付费的呢?按查询次数收费的话,又会如何设计呢?
那就不是“别问我,问他”了,而是“只有我对”。
可能就是各个公司互相摸黑攻击争利,阻挠新技术,千方百计减少缓存,恨不得连主机本地缓存都给砍了。
思考:为什么114的号码查询现在几乎没有存在感了呢?
问:本地主机能不能直接向根域服务器进行查询?
答:可以,正如群众如果会英语就可以直接和小白进行查询同理。只不过主机操作系统一般没有都没有内置根域的清单,也没有附带可以解决“问他”逻辑的专用软件。需要自己另外安装软件。
问:本地DNS服务器是否可以不经过根域服务器就完成查询?
答:可以,前提是它有一份准确的子域(顶级域)的清单。想想看,这显然是不可能的。
不过单独配置几个常用顶级域的地址,如(com,cn,net)这几个也能有效果,但很难确保地址变更时能及时同步上。