關(guān)于GitHub的DNS基礎(chǔ)設(shè)施,你了解嗎?
在 GitHub,我們最近從頭改進(jìn)了 DNS。這包括了我們?nèi)绾闻c外部 DNS 提供商交互以及我們?nèi)绾卧趦?nèi)部向我們的主機(jī)提供記錄。為此,我們必須設(shè)計(jì)和構(gòu)建一個(gè)新的 DNS 基礎(chǔ)設(shè)施,它可以隨著 GitHub 的增長(zhǎng)擴(kuò)展并跨越多個(gè)數(shù)據(jù)中心。
以前,GitHub 的 DNS 基礎(chǔ)設(shè)施相當(dāng)簡(jiǎn)單直接。它包括每臺(tái)服務(wù)器上本地的、只具備轉(zhuǎn)發(fā)功能的 DNS 緩存服務(wù)器,以及一對(duì)被所有這些主機(jī)使用的緩存服務(wù)器和權(quán)威服務(wù)器主機(jī)。這些主機(jī)在內(nèi)部網(wǎng)絡(luò)以及公共互聯(lián)網(wǎng)上都可用。我們?cè)诰彺媸刈o(hù)程序中配置了區(qū)域zone存根stub,以在本地進(jìn)行查詢,而不是在互聯(lián)網(wǎng)上進(jìn)行遞歸。我們還在我們的 DNS 提供商處設(shè)置了 NS 記錄,它們將特定的內(nèi)部域domain指向這對(duì)主機(jī)的公共 IP,以便我們網(wǎng)絡(luò)外部的查詢。
這個(gè)配置使用了很多年,但它并非沒(méi)有缺點(diǎn)。許多程序?qū)τ诮馕?DNS 查詢非常敏感,我們遇到的任何性能或可用性問(wèn)題在***的情況下也會(huì)導(dǎo)致服務(wù)排隊(duì)和性能降級(jí),而最壞情況下客戶會(huì)遭遇服務(wù)中斷。配置和代碼的更改可能會(huì)導(dǎo)致查詢率發(fā)生大幅度的意外變化。因此超出這兩臺(tái)主機(jī)的擴(kuò)展成為了一個(gè)問(wèn)題。由于這些主機(jī)的網(wǎng)絡(luò)配置,如果我們只是繼續(xù)添加 IP 和主機(jī)的話存在一些本身的問(wèn)題。在試圖解決和補(bǔ)救這些問(wèn)題的同時(shí),由于缺乏測(cè)量指標(biāo)和可見(jiàn)性,老舊的系統(tǒng)難以識(shí)別問(wèn)題的原因。在許多情況下,我們使用 tcpdump 來(lái)識(shí)別有問(wèn)題的流量和查詢。另一個(gè)問(wèn)題是在公共 DNS 服務(wù)器上運(yùn)行,我們處于泄露內(nèi)部網(wǎng)絡(luò)信息的風(fēng)險(xiǎn)之下。因此,我們決定建立更好的東西,并開(kāi)始確定我們對(duì)新系統(tǒng)的要求。
我們著手設(shè)計(jì)一個(gè)新的 DNS 基礎(chǔ)設(shè)施,以改善上述包括擴(kuò)展和可見(jiàn)性在內(nèi)的運(yùn)維問(wèn)題,并引入了一些額外的需求。我們希望通過(guò)外部 DNS 提供商繼續(xù)運(yùn)行我們的公共 DNS 域,因此我們構(gòu)建的系統(tǒng)需要與供應(yīng)商無(wú)關(guān)。此外,我們希望該系統(tǒng)能夠服務(wù)于我們的內(nèi)部和外部域,這意味著內(nèi)部域僅在我們的內(nèi)部網(wǎng)絡(luò)上可用,除非另有特別配置,而外部域也不用離開(kāi)我們的內(nèi)部網(wǎng)絡(luò)就可解析。我們希望新的 DNS 架構(gòu)不但可以基于部署的工作流進(jìn)行更改,并可以通過(guò)我們的倉(cāng)庫(kù)和配置系統(tǒng)使用 API 自動(dòng)更改 DNS 記錄。新系統(tǒng)不能有任何外部依賴,太依賴于 DNS 功能將會(huì)陷入級(jí)聯(lián)故障,這包括連接到其他數(shù)據(jù)中心和其中可能有的 DNS 服務(wù)。我們的舊系統(tǒng)將緩存服務(wù)器和權(quán)威服務(wù)器在同一臺(tái)主機(jī)上混合使用。我們想轉(zhuǎn)到具有獨(dú)立角色的分層設(shè)計(jì)。***,我們希望系統(tǒng)能夠支持多數(shù)據(jù)中心環(huán)境,無(wú)論是 EC2 還是裸機(jī)。
實(shí)現(xiàn)
為了構(gòu)建這個(gè)系統(tǒng),我們確定了三類主機(jī):緩存主機(jī)cache、邊緣主機(jī)edge和權(quán)威主機(jī)authority。緩存主機(jī)作為遞歸解析器recursive resolver和 DNS “路由器” 緩存來(lái)自邊緣層的響應(yīng)。邊緣層運(yùn)行 DNS 權(quán)威守護(hù)程序,用于響應(yīng)緩存層對(duì) DNS 區(qū)域zone的請(qǐng)求,其被配置為來(lái)自權(quán)威層的區(qū)域傳輸zone transfer。權(quán)威層作為隱藏的 DNS 主服務(wù)器master,作為 DNS 數(shù)據(jù)的規(guī)范來(lái)源,為來(lái)自邊緣主機(jī)的區(qū)域傳輸zone transfer提供服務(wù),并提供用于創(chuàng)建、修改或刪除記錄的 HTTP API。
在我們的新配置中,緩存主機(jī)存在于每個(gè)數(shù)據(jù)中心中,這意味著應(yīng)用主機(jī)不需要穿過(guò)數(shù)據(jù)中心邊界來(lái)檢索記錄。緩存主機(jī)被配置為將區(qū)域zone映射到其地域region內(nèi)的邊緣主機(jī),以便將我們的內(nèi)部區(qū)域zone路由到我們自己的主機(jī)。未明確配置的任何區(qū)域zone將通過(guò)互聯(lián)網(wǎng)遞歸解析。
邊緣主機(jī)是地域性的主機(jī),存在我們的網(wǎng)絡(luò)邊緣 PoP(存在點(diǎn)Point of Presence)內(nèi)。我們的 PoP 有一個(gè)或多個(gè)依賴于它們進(jìn)行外部連接的數(shù)據(jù)中心,沒(méi)有 PoP 數(shù)據(jù)中心將無(wú)法訪問(wèn)互聯(lián)網(wǎng),互聯(lián)網(wǎng)也無(wú)法訪問(wèn)它們。邊緣主機(jī)對(duì)所有的權(quán)威主機(jī)執(zhí)行區(qū)域傳輸zone transfer,無(wú)論它們存在什么地域region或位置location,并將這些區(qū)域存在本地的磁盤(pán)上。
我們的權(quán)威主機(jī)也是地域性的主機(jī),只包含適用于其所在地域region的區(qū)域zone。我們的倉(cāng)庫(kù)和配置系統(tǒng)決定一個(gè)區(qū)域zone存放在哪個(gè)地域性權(quán)威主機(jī)regional authority,并通過(guò) HTTP API 服務(wù)來(lái)創(chuàng)建和刪除記錄。 OctoDNS 將區(qū)域映射到地域性權(quán)威主機(jī),并使用相同的 API 創(chuàng)建靜態(tài)記錄,以及確保動(dòng)態(tài)源處于同步狀態(tài)。對(duì)于外部域 (如 github.com),我們有另外一個(gè)單獨(dú)的權(quán)威主機(jī),以允許我們可以在連接中斷期間查詢我們的外部域。所有記錄都存儲(chǔ)在 MySQL 中。
可運(yùn)維性
遷移到更現(xiàn)代的 DNS 基礎(chǔ)設(shè)施的巨大好處是可觀察性。我們的舊 DNS 系統(tǒng)幾乎沒(méi)有指標(biāo),只有有限的日志。決定使用哪些 DNS 服務(wù)器的一個(gè)重要因素是它們所產(chǎn)生的指標(biāo)的廣度和深度。我們最終用 Unbound 作為緩存主機(jī),NSD 作為邊緣主機(jī),PowerDNS 作為權(quán)威主機(jī),所有這些都已在比 GitHub 大得多的 DNS 基礎(chǔ)架構(gòu)中得到了證實(shí)。
當(dāng)在我們的裸機(jī)數(shù)據(jù)中心運(yùn)行時(shí),緩存通過(guò)私有的任播anycast IP 訪問(wèn),從而使之可以到達(dá)最近的可用緩存主機(jī)。緩存主機(jī)已經(jīng)以機(jī)架感知的方式部署,在它們之間提供了一定程度的平衡負(fù)載,并且與一些電源和網(wǎng)絡(luò)故障模式相隔離。當(dāng)緩存主機(jī)出現(xiàn)故障時(shí),通常將用其進(jìn)行 DNS 查詢的服務(wù)器現(xiàn)在將自動(dòng)路由到下一個(gè)最接近的緩存主機(jī),以保持低延遲并提供對(duì)某些故障模式的容錯(cuò)。任播允許我們擴(kuò)展單個(gè) IP 地址后面的緩存數(shù)量,這與先前的配置不同,使得我們能夠按 DNS 需求量運(yùn)行盡可能多的緩存主機(jī)。
無(wú)論地域或位置如何,邊緣主機(jī)使用權(quán)威層進(jìn)行區(qū)域傳輸。我們的區(qū)域zone并沒(méi)有大到在每個(gè)地域region保留所有區(qū)域zone的副本成為問(wèn)題。(LCTT 譯注:此處原文“Our zones are not large enough that keeping a copy of all of them in every region is a problem.”,根據(jù)上下文理解而翻譯。)這意味著對(duì)于每個(gè)區(qū)域,即使某個(gè)地域處于脫機(jī)狀態(tài),或者上游服務(wù)提供商存在連接問(wèn)題,所有緩存服務(wù)器都可以訪問(wèn)具備所有區(qū)域的本地副本的本地邊緣服務(wù)器。這種變化在面對(duì)連接問(wèn)題方面已被證明是相當(dāng)有彈性的,并且在不久前本來(lái)會(huì)導(dǎo)致客戶面臨停止服務(wù)的故障期間幫助保持 GitHub 可用。
那些區(qū)域傳輸包括了內(nèi)部和外部域從它們相應(yīng)的權(quán)威服務(wù)器進(jìn)行的傳輸。正如你可能會(huì)猜想像 github.com 這樣的區(qū)域是外部的,像 github.net 這樣的區(qū)域通常是內(nèi)部的。它們之間的區(qū)別僅在于我們使用的類型和存儲(chǔ)在其中的數(shù)據(jù)。了解哪些區(qū)域是內(nèi)部和外部的,為我們?cè)谂渲弥刑峁┝艘恍╈`活性。
- $ dig +short github.com
- 192.30.253.112
- 192.30.253.113
公共區(qū)域zone被同步到外部 DNS 提供商,并且是 GitHub 用戶每天使用的 DNS 記錄。另外,公共區(qū)域在我們的網(wǎng)絡(luò)中是完全可解析的,而不需要與我們的外部提供商進(jìn)行通信。這意味著需要查詢 api.github.com 的任何服務(wù)都可以這樣做,而無(wú)需依賴外部網(wǎng)絡(luò)連接。我們還使用了 Unbound 的 stub-first 配置選項(xiàng),它給了我們第二次查詢的機(jī)會(huì),如果我們的內(nèi)部 DNS 服務(wù)由于某些原因在外部查詢失敗,則可以進(jìn)行第二次查找。
- $ dig +short time.github.net
- 10.127.6.10
大部分的 github.net 區(qū)域是完全私有的,無(wú)法從互聯(lián)網(wǎng)訪問(wèn),它只包含 RFC 1918 中規(guī)定的 IP 地址。每個(gè)地域和站點(diǎn)都劃分了私有區(qū)域。每個(gè)地域和/或站點(diǎn)都具有適用于該位置的一組子區(qū)域,子區(qū)域用于管理網(wǎng)絡(luò)、服務(wù)發(fā)現(xiàn)、特定的服務(wù)記錄,并且還包括在我們倉(cāng)庫(kù)中的配置主機(jī)。私有區(qū)域還包括 PTR 反向查找區(qū)域。
總結(jié)
用一個(gè)新系統(tǒng)替換可以為數(shù)百萬(wàn)客戶提供服務(wù)的舊系統(tǒng)并不容易。使用實(shí)用的、基于需求的方法來(lái)設(shè)計(jì)和實(shí)施我們的新 DNS 系統(tǒng),才能打造出一個(gè)能夠迅速有效地運(yùn)行、并有望與 GitHub 一起成長(zhǎng)的 DNS 基礎(chǔ)設(shè)施。
想幫助 GitHub SRE 團(tuán)隊(duì)解決有趣的問(wèn)題嗎?我們很樂(lè)意你加入我們。在這申請(qǐng)。