更多精彩文章,请关注作者的微信公众号:码工笔记
背景
北京时间10月4日23:50到10月5日5:20之间(15:50~21:20 UTC),Facebook公司旗下所有网站及应用,包括facebook、instagram、whatsapp等都出现了网络无法连接的严重事故。
经过几个小时的抢修,系统恢复正常后,Facebook自己以及Cloudflare等公司各自从内部、外部视角对事故原因进行了解释和分析。
我们正好借这个机会学习/复习一下相关的网络基础知识。
事故原因
据FB官方技术博客的说法[1],事故的直接原因如下:
-
某工程师运行了一个用于评估FB内部骨干网容量可用性的脚本,此脚本意外导致骨干网上的所有设备都被断开连接,也即FB数据中心的所有服务器之间以及其与外部Internet全部断连。
-
同时,FB的DNS官方域名服务器是独立维护的,有其固定IP地址,它通过BGP协议将自己的IP段广播出去,从而让外部网络知道自己并将相关的请求发送给它。在其DNS域名服务器内部有个故障检测逻辑是:如果它发现自己无法连接FB的数据中心,则停止广播其BGP。
在数据中心全部断连的情况下,FB的DNS服务器发现自己无法成功与数据中心连接,进而认为自己的网络出了问题,于是主动停止了BGP对自己IP段的广播,导致外部无法连接FB DNS服务器。
-
由于DNS无法工作,FB内部一些诊断工具也无法使用,必须派工程师到机房现场才能解决,进一步延长了宕机时间。
下面,我们主要就DNS和BGP这两个知识点进行学习和回顾。
DNS解析
DNS(域名解析服务器)主要用于将域名转换为IP地址,可以使用dig命令来查询域名相关的信息。
查询facebook.com的域名信息的命令如下,具体返回字段说明见注释部分(//):
$ dig facebook.com +noall +answer +stat
; <<>> DiG 9.10.6 <<>> facebook.com +noall +answer +stat
;; global options: +cmd
//返回各字段说明如下:
//域名 缓存失效时间(TTL) 网络类别 TYPE VALUE
facebook.com. 45 IN A 162.125.2.6
//注:其中TYPE为A(Address)表示后面是一个地址。
;; Query time: 5 msec
//这里告诉我们使用的SERVER用的是192.168.3.1,53是DNS使用的UDP端口号
;; SERVER: 192.168.3.1#53(192.168.3.1)
;; WHEN: Tue Oct 12 01:50:58 CST 2021
;; MSG SIZE rcvd: 46
dig 默认使用 /etc/resolve.conf 文件中配置的域名服务器:
$ cat /etc/resolv.conf
nameserver fe80::960e:6bff:fea9:479a
nameserver 192.168.3.1
也可以在命令行中显式指定域名服务器:
//指定使用 8.8.8.8 作为域名服务器来解析域名
$ dig @8.8.8.8 facebook.com
不过,类似8.8.8.8(Google)的这些服务器也并不能知道所有的域名和IP地址的对应关系,实际上,全世界数以亿计的域名信息分布在无数的域名服务器上,我们可以用 dig ns 来看一下维护facebook.com域名信息的服务器是哪些:
$ dig facebook.com ns +noall +answer
; <<>> DiG 9.10.6 <<>> facebook.com ns +noall +answer
;; global options: +cmd
//NS代表Name Server(域名服务器),最后一个字段代表域名服务器地址
facebook.com. 103522 IN NS a.ns.facebook.com.
facebook.com. 103522 IN NS b.ns.facebook.com.
facebook.com. 103522 IN NS c.ns.facebook.com.
facebook.com. 103522 IN NS d.ns.facebook.com.
上面我们知道,dig会默认请求域名服务器192.168.3.1关于facebook.com的域名信息,而a.ns.facebook.com等服务器保存了facebook.com的具体域名信息,那么192.168.3.1是如何联系上a.ns.facebook.com的呢?
我们可以使用 dig 命令的 +trace 选项来打印出域名解析的具体过程:
$ dig +trace facebook.com
其输出结果分段解析如下:
; <<>> DiG 9.10.6 <<>> +trace facebook.com
;; global options: +cmd
. 275678 IN NS f.root-servers.net.
. 275678 IN NS d.root-servers.net.
. 275678 IN NS e.root-servers.net.
. 275678 IN NS b.root-servers.net.
. 275678 IN NS c.root-servers.net.
. 275678 IN NS i.root-servers.net.
. 275678 IN NS l.root-servers.net.
. 275678 IN NS j.root-servers.net.
. 275678 IN NS m.root-servers.net.
. 275678 IN NS k.root-servers.net.
. 275678 IN NS a.root-servers.net.
. 275678 IN NS h.root-servers.net.
. 275678 IN NS g.root-servers.net.
;; Received 228 bytes from 192.168.1.1#53(192.168.1.1) in 7 ms
注意这里192.168.1.1是当前局域网内的联通路由器,它内部记录了13台全球根域名(".")服务器的地址。
细心的读者会发现 resolve.conf中指定的192.168.3.1,而这里是192.168.1.1。这是因为我这里有两台路由器,电脑使用的WIFI是由一台华为路由器(192.168.3.1)提供的,华为路由器又连到了联通路由器(192.168.1.1)上,并且在华为路由器的配置页面中指定了其DNS为192.168.1.1。
以下继续向这13台全球根域名服务器请求 .com 顶级域名服务器地址,以最先回复的为准。
com. 172800 IN NS a.gtld-servers.net.
com. 172800 IN NS b.gtld-servers.net.
com. 172800 IN NS c.gtld-servers.net.
com. 172800 IN NS d.gtld-servers.net.
com. 172800 IN NS e.gtld-servers.net.
com. 172800 IN NS f.gtld-servers.net.
com. 172800 IN NS g.gtld-servers.net.
com. 172800 IN NS h.gtld-servers.net.
com. 172800 IN NS i.gtld-servers.net.
com. 172800 IN NS j.gtld-servers.net.
com. 172800 IN NS k.gtld-servers.net.
com. 172800 IN NS l.gtld-servers.net.
com. 172800 IN NS m.gtld-servers.net.
com. 86400 IN DS 30909 8 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CF C41A5766
com. 86400 IN RRSIG DS 8 1 86400 20211022050000 20211009040000 14748 . fcKx2jK2VQRHTjWXC3GXgRMnnDDdOFse96oeGZzPK6nrNc5iGCsUs7kB t4uKF03f5cepLSHEl+BfzhLNk/RiMlm5yR85NuiktsusWrmYMfwIqcOO UAZesk6HfVMxpk4Wl7bkT7gqWA9B4dwTjorzSJWHHaxm6PL6tBqUbD2p mFVARK7R5l4qyIXDtxtpXUCSCS6gRE8MKhxNRv11GwUU8DZju+KH9s+B BXCLoX9H12p/iemkvpU9VPCZUSmaLjZdCbS0TEEWoXofGI0lkOYAF1mt oj420RygKS9kJSBud/U9jbUPa67z0rVrfAMEZdKpLpOFRvgnp1iAmJ13 JkUFYw==
;; Received 1172 bytes from 199.7.83.42#53(l.root-servers.net) in 7 ms
这里l.root-servers.net最先回复,返回13台.com顶级域名服务器的域名和地址。
以下继续向这些.com顶级域名服务器请求查询facebook.com二级域名服务器地址
facebook.com. 172800 IN NS a.ns.facebook.com.
facebook.com. 172800 IN NS b.ns.facebook.com.
facebook.com. 172800 IN NS c.ns.facebook.com.
facebook.com. 172800 IN NS d.ns.facebook.com.
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - CK0Q1GIN43N1ARRC9OSM6QPQR81H5M9A NS SOA RRSIG DNSKEY NSEC3PARAM
CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20211015042328 20211008031328 39343 com. H1oBuRZXju7c+fi2/am00pD0N4j8e+g/Q+qDd5/NHtSA+OhdRG2BcmXk m1cjsA50akyzYQmKzfAE/1msrzkiULmh23LjZ3P53/mLUBtDIVOXkN2F 5nuSGSpv7Ngvn6vGsHXukdZpG97b9lSgqnv1FgRPWedEVjOdD0FMJBbc XikWESWI5Ue0vBj3oxfS24gww4tLXSOHjtLjGapaphWZ1g==
I28G6CI6H7LILO18C929Q5HCLS95D2FC.com. 86400 IN NSEC3 1 1 0 - I28GTDKPVCUQGJKUK7EP5QM6TTI5TO3A NS DS RRSIG
I28G6CI6H7LILO18C929Q5HCLS95D2FC.com. 86400 IN RRSIG NSEC3 8 2 86400 20211014044832 20211007033832 39343 com. D3APaNt+ZOxCHupj+tyNPTUrtS+Kq1d2tI2ZJiI9R7WREYO+I56zzvhh zNkttftMmUekNVCGHILNww/ekuabwLcRKyg7Bs/YowpcXr3LgB0UZDVB bj4GtUMC8s52nuPU6pIH6iHgZ04cq9E3MCCep9H9RbX3dYmUXDLVBWcJ DoAY1vEtdCZKVKjYvGr3dNYF0JpUiKkqBvtTJwpA34W1lA==
;; Received 833 bytes from 2001:503:d2d::30#53(k.gtld-servers.net) in 179 ms
最先回复的是 k.gtld-servers.net,它返回了 Facebook 的4个域名服务器:
- a.ns.facebook.com
- b.ns.facebook.com
- c.ns.facebook.com
- d.ns.facebook.com 另外,这里可以看到,facebook.com对应的TTL都是172800,也就是48小时(后文会用到)。
以下继续向这4台域名服务器请求A记录(即IP地址):
facebook.com. 105 IN A 157.240.2.50
;; Received 46 bytes from 2001::67fc:720b#53(c.ns.facebook.com) in 11 ms
最先回复的是 c.ns.facebook.com,得到facebook.com的IP地址为157.240.2.50。
注:在此次事故发生时,因为4个DNS服务器都撤消了BGP广播,所以都无法连接,反映到 dig 命令里就是当前这一步会超时失败。以下是CloudFare工程师当时用dig取得的错误信息(SERVFAIL):
➜ ~ dig @1.1.1.1 facebook.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 31322
;facebook.com. IN A
➜ ~ dig @8.8.8.8 facebook.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 31322
;facebook.com. IN A
DNS缓存
为了减轻DNS根服务器的压力,且考虑到域名和IP的对应关系其实不会太频繁地变化,因此各个域名服务器可以缓存之前请求过的域名A记录。基于此,对于一个特定的域名来说,域名服务器可以分为两类:
- 权威域名服务器(Authoritative Name Server),真正负责维护该域名信息的服务器
- 缓存域名服务器,仅缓存域名信息 如果本地或递归查找过程中没有缓存,则它会最终到权威域名服务器获取域名信息。如果有缓存,而权威域名服务器上的信息发生了更新,这时可能会取到过期的信息,如果需要获取最新的信息,可以使用 @权威服务器地址 的形式强制指定从权威服务器获取,否则就只能等待缓存记录的TTL失效。
讲到这里,我们先看一下 amazon.com 的域名服务器是如何设置的:
$ dig ns amazon.com +noall +answer
; <<>> DiG 9.10.6 <<>> ns amazon.com +noall +answer
;; global options: +cmd
amazon.com. 800 IN NS pdns1.ultradns.net.
amazon.com. 800 IN NS ns4.p31.dynect.net.
amazon.com. 800 IN NS ns3.p31.dynect.net.
amazon.com. 800 IN NS ns2.p31.dynect.net.
amazon.com. 800 IN NS ns1.p31.dynect.net.
amazon.com. 800 IN NS pdns6.ultradns.co.uk.
可以看出为了保证稳定性, amazon 很有意思地用了两家外部DNS提供商来维护它的域名信息。
可能会有同学有疑问,为什么FB DNS发生故障时,不能直接换一个外部的DNS服务提供商临时提供一下域名转换呢?
原因就是:facebook.com 的域名服务器由顶级域名服务器(TLD)维护,顶级域名一般设置的过期时间较长,上文看到是48小时,也就是说即使临时换了外部DNS服务商,有些用户需要两天才能连接到Facebook,这种方案实操上不可行。
BGP
上文几次提到了BGP,这里我们介绍一下BGP相关的知识。
要了解BGP,首先我们要了解自治系统(AS)。
自治系统(AS)
自治系统(Autonomous System)是指在一个实体管辖下的拥有相同路由策略的IP网络。
-
BGP网络中的每个AS都被分配一个唯一的AS号
-
有2字节和4字节的AS号,范围分别为1-65535和1-4294967295,4字节可兼容2字节
-
Facebook.com:AS32934
-
-
有些网站提供了通过域名来查询AS号的服务[8]
一般来说大型公司可能会申请一个或多个独立的AS号。
网络上的各结点要实现互联,就需要路由协议,依照作用范围可将路由协议分为以下两类:
-
IGP:用于AS内部的路由协议,如:RIP,OSPF,IS-IS等
-
EGP:用于AS之间的路由协议,主要是BGP
BGP协议
边界网关协议(BGP,Border Gateway Protocol)是运行在TCP上的一种自治系统(AS)的路由协议,用于实现AS间路由信息的交互。
BGP协议特征:
-
使用TCP作为传输协议(端口号179),BGP路由器之间基于TCP建立会话,BGP对等体间无需直连
-
运行BGP的路由器称为BGP Speaker,两台BGP路由器需建立对等体关系才能交互BGP路由,存在两种类型的BGP对等体关系:EBGP & IBGP:
-
EBGP:运行于不同AS之间的BGP
-
IBGP:同一AS内部的路由器之间使用的BGP
-
-
BGP对等体关系建立完成后,只发送增量更新或触发更新(不会周期性性更新)
-
BGP具有丰富的路径属性和强大的策略工具
-
BGP能承载大批量的路由前缀,用于大规模的网络中
拿FB来说,其内部有几百万台服务器,形成了一个庞大的内部网络(AS),有自己的路由管理机制。 当客户端应用通过IP地址128.242.240.20来访问FB内部的www.facebook.com的服务器时,这些IP报文会先经由用户的网络提供商(ISP)的接入点发送到公网路由器,公网路由器需要根据路由算法,找到通往FB内部服务器的最短路径。而因为FB内部是一个自治网络(AS),路由的“最后一公里”只能由FB的路由器来完成,即公网路由只需要将包发送给FB的路由器,由FB路由器来负责内部最终的路由任务。
那么公网路由器如何找到通往FB路由器的路呢?
BGP协议就是为了这一目的而设计的,根据BGP协议,FB的BGP路由器可以通过发送相应的UPDATE消息给它的对等体(公网路由器),告诉它们自己负责哪些IP段,这些信息会递归地传给这些路由器的其他对等体,这样递归传下去,所有的公网路由器就都能知道一条或多条通往FB的路由器的路径(AS_Path),当后续这些公网路由器收到发给这些IP段的包时就会沿着最优路径将包转发给FB路由器。
我们可以用telnet登录route-views.isc.routeviews.org这样的模拟路由器来观察一下BGP具体的配置信息[12]:
$ telnet route-views.isc.routeviews.org
Trying 149.20.4.24...
Connected to route-views.isc.routeviews.org.
Escape character is '^]'.
Hello, this is FRRouting (version 7.3-rv).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
route-views.isc.routeviews.org> show ip bgp 31.13.80.36
BGP routing table entry for 31.13.80.0/24
Paths: (6 available, best #4, table default)
Not advertised to any peer
30286 3356 1299 32934
198.32.176.142 from 198.32.176.142 (10.2.1.2)
Origin IGP, valid, external
Community: 3356:3 3356:22 3356:86 3356:575 3356:666 3356:901 3356:2011
Last update: Sun Sep 26 12:53:14 2021
199524 1299 32934
198.32.176.226 from 198.32.176.226 (10.255.65.68)
Origin IGP, valid, external
Last update: Thu Jul 22 07:09:01 2021
19151 174 32934
198.32.176.164 from 198.32.176.164 (66.186.193.17)
Origin IGP, metric 0, valid, external
Last update: Fri Aug 6 07:29:28 2021
6939 32934
198.32.176.20 from 198.32.176.20 (216.218.252.165)
Origin IGP, valid, external, best (Older Path)
Last update: Tue Jun 29 12:08:27 2021
7575 2914 174 32934
198.32.176.177 from 198.32.176.177 (202.158.215.120)
Origin IGP, valid, external
Community: 7575:1003 7575:2520 7575:6003
Last update: Tue Jun 29 14:29:41 2021
36351 32934
198.32.176.207 from 198.32.176.207 (173.192.18.26)
Origin IGP, valid, external
Community: 36351:202 65501:140 65523:200
Last update: Sat Aug 28 10:27:27 2021
其中31.13.80.36是Facebook的一台服务器IP,从上面的信息可以看出由当前路由器到Facebook的AS32934一共有6条路径,其中第4条是最佳路径:
-
30286 3356 1299 32934
-
199524 1299 32934
-
19151 174 32934
-
6939 32934 (最佳)
-
7575 2914 174 32934
-
36351 32934 当IP包到达此路由器时,它就会照着最佳路径转发出去,直到到达FB的AS32934。
BGP路由通告规则:
-
当到达同一目的地存在多条路径时,BGP路由器只选取最优的路由来使用(未开启负载均衡的情况下)
-
BGP只把自己使用的路由(也即自己认为的最优路由)传递给对等体
-
BGP路由器从EBGP对等体获得的路由会向它所有的BGP对等体通告(包括EBGP和IBGP)
-
BGP路由器从IBGP对等体获知的路由不向它的IBGP对等体通告(水平分割规则,存在路由反射器的情况除外)
-
BGP路由器从IBGP对等体获知的路由是否通告给它的EBGP对等体要视IGP和BGP同步的情况来决定
-
路由更新时,BGP设备只发送更新的BGP路由
BGP报文类型:
-
OPEN:TCP连接建立后发送的第一个报文
-
UPDATE:对于在对等体之间交换路由信息(可以发布可达路由,也可以撤销不可达路由信息)
-
NOTIFICATION:BGP检测到错误状态时向对等体发出此消息,之后BGP连接会立即中断
-
KEEPALIVE:维持对等体关系
-
Route-refresh:当路由策略发生变化时,用来要求对等体重新发送指定地址族的路由信息
据Cloudflare的分析报告,这次FB故障发生时,FB侧的BGP路由器发送了很多UPDATE消息,其中很大一部分是用于撤销路由[2]。
注:通过BGPlay网站[11]可以看到指定ASN或IP段的BGP具体消息的历史和实时的变化。
上图可以看到2021-10-04 13:51时AS连接正常,从FB的AS32934跟很多别的AS都有连接。
但在16:12(即第一个尖峰过去)之后,32934与别的AS都断开了连接,这时facebook的服务器已经全部连不上了。
然后在22:00以后,与其他AS连接又都恢复了,这时候FB的服务已经全面恢复。图中用红框标出了出问题时和恢复时的两段尖峰,这两个尖峰代表的是AS32934在这段时间内发出了大量的UPDATE消息。
参考资料
- engineering.fb.com/2021/10/05/…
- blog.cloudflare.com/october-202…
- www.thousandeyes.com/blog/facebo…
- baijiahao.baidu.com/s?id=160398…
- zhuanlan.zhihu.com/p/25433049
- www.jianshu.com/p/babca8224…
- zhuanlan.zhihu.com/p/51684918
- 通过域名查询ASN:bgp.he.net
- whois查询:mip.chinaz.com/Ip/IpWhois
- www.cnblogs.com/sikewang/p/…
- BGPlay:stat.ripe.net/widget/bgpl…
- jvns.ca/blog/2021/1…