虎牙在全球 DNS 秒級生效上的實踐

這次分享的是全球 DNS 秒級生效在虎牙的實踐,以及由此產生的一些思考,整體上,分爲以下5各部分:

背景介紹;
方案設計和對比;
高可用;
具體實踐和落地;
規劃;
背景介紹
虎牙用到的基礎技術很多,DNS 是其中比較重要的一個環節。

虎牙在全球 DNS 秒級生效上的實踐

DNS 的解析過程很關鍵,例如上圖中的 DNS 解析器通過一個定位解析追蹤到我們的 DNS,再到本地域名服務器迭代解析,經過根域再到.com名,最後到huya.com的根域名,獲取最終的解析結果。

在這個過程中, DNS解析是天然的分佈式架構,每一層都會有緩存,上一層出現問題掛掉,下一層都會有緩存進行容災。另外,整個 DNS 協議支持面廣,包括手機和 PC,我們用的編程框架裏也有 DNS 解析器,服務器也會配 DNS 解析引擎,因此,DNS 在虎牙的基礎設施中是很重要的部分。

虎牙的 DNS 的應用現狀
虎牙當前主要是依賴於公共的 DNS,相信在座的小夥伴們或多或少都會遇到過下面這些問題:

依賴公共 localDNS,解析不穩定,延遲大。
記錄變更生效時間長,無法及時屏蔽線路和節點異常對業務的影響。例如,權威 DNS 全球各節點數據同步時間不可控,全局生效時間超過10分鐘;localDNS 緩存過期時間不可控,部分 localDNS 不遵循TTL時間,緩存時間超過48小時。
內部 DNS 功能缺失,無法解決內部服務調用面臨挑戰。例如,時延大、解析不準、支持多種調度策略。
無法滿足國外業務的快速發展,雖然一些海外雲廠商提供了基於 DNS 的快速擴容方案,以及基於 DNS 的數據庫切換方案。
方案設計和對比
基於以上的問題,我們開始重新規劃 DNS 的設計。

名字服務架構
虎牙在全球 DNS 秒級生效上的實踐

整個規劃會分三個方面,核心是我們做了「名字服務」的中心點,基於此,可以滿足我們的需求。

一方面通過 Nacos Sync,將現有多個註冊中心的服務, 同步到「名字服務」中, 通過 DNS 實現不同框架之間的 Rest 服務方式的調用, 實現例如 Eureka,Consul,Taf等框架之間的服務調用。

另一方面,在全球負載均衡的場景下,由於虎牙是以音視頻業務爲主,而音視頻業務對節點的延遲是非常敏感的,所以我們希望一旦出現節點延遲的情況,能立馬做切換。

第三個是傳統 DNS 的場景, 可以滿足容器和物理機的 DNS 需求, 提供本機 Agent 和集羣兩種方案, 通過緩存和 prefect 大大提高 DNS 解析的可用性和加快生效時間。

虎牙在全球 DNS 秒級生效上的實踐

對於名字服務的總體設計主要分3部分,接入層需要提供 API,消息通知和 DNS 接入的能力。核心功能需要能在基於現有網絡數據,CMDB 和 IP 庫的數據基礎上,提供靈活的負載均衡能力,全球數據的秒級同步,多個數據源的同步,能對全網服務的健康狀態進行監控,及時感知到大範圍的節點異常,並且能夠及時將節點的屏蔽的信息推送到端上。

最終,我們選擇 Nacos 作爲名字服務的核心,提供統一的 API ,包括名字註冊、變化推送、負載均衡等;Nacos Sync 作爲全球集羣間數據同步的組件;DNS - F是客戶端組件,用於攔截 DNS 請求,實現基於 DNS 的名字服務。

改造前後 DNS 變更生效流程的不同
接下來,我們通過對比看下改造前後 DNS 變更生效流程的差異。

虎牙在全球 DNS 秒級生效上的實踐

原有 DNS 變更生效流程中,對 DNS 生效時間有影響的是:

Auth DNS:

跨區域、跨國數據同步慢,不穩定。

bind 在數據量比較大的時候,同步比較慢。

Local DNS:

根據 TTL 緩存,過期後纔會刷新數據。

部分廠商不遵循 TTL 時間緩存,超過24小時的緩存時間。

服務器:

服務器開啓 nscd 做 DNS 緩存。

業務進程:

應用的 DNS 緩存,比如 Java 虛擬機、框架層的 DNS 緩存。

以上四種情況會比較影響 DNS 的變更生效流程,下圖是我們現有的 DNS 變更生效流程:

虎牙在全球 DNS 秒級生效上的實踐

整體上相對簡單,只要業務進程這邊將自己內部的 DNS 緩存關掉, 通過 DNS-F 進行查詢的時候, 會直接到最近的 Nacos 集羣拉取最新的服務節點信息, 而且後續節點的變化也會推送到 DNS-F 中, 後續可以直接在緩存中獲取最新信息。

國內 Nacos 集羣:

集羣內通過 raft 協議同步數據,毫秒級別完成同步。

Nacos Sync:

Nacos 推送變化到 Nacos Sync,跨區域、跨國網絡差的情況下可能會導致推送結果丟失,或者延遲加大。

Nacos Sync 會主動拉取實例變更,拉取週期和監聽的服務數量會影響到變更時效。

DNS - F:

Nacos 會將變更推送到 DNS - F,網絡差的情況可能會導致推送結果丟失,或者延遲加大。

DNS - F 會主動拉取實例變更,拉取週期和監聽的服務數量會影響到變更時效。

業務進程:

通過應用禁用 DNS 緩存來解決。

核心設計 Nacos
Nacos 有兩套推送機制。

虎牙在全球 DNS 秒級生效上的實踐

一種是通過客戶端來選擇一個可獲節點,比如它第一次拉取的是一個正常節點,這個正常節點就會跟它維護一個訂閱關係,後面有變化就會有一個相應的實地變化推送給我。如果當前節點掛掉, 他會通過重連, 在節點列表上,連上一個正常的節點。這時候會有新的 DNS 關係出現。

另一種是通過 SDK 的方式,在服務端尋找可獲節點。服務端每個節點之間, 會進行一個可活的探測, 選擇其中一個可活節點用戶維護這個訂閱關係。 當這個節點出現問題, 連接斷開後, SDK 重新發送訂閱請求,服務端會再次選擇另外一個可活的節點來維護這個訂閱關係。這就保證整了推送過程不會因爲某個節點掛掉而沒有推送。

推送的效率方面,主要是用 UDP 的方式,這個效率不像 TCP 消耗那麼高。

以上兩個方案都比較適合我們目前的場景。

核心組件設計 Nacos Sync
我們選擇 Nacos Sync 作爲多集羣數據同步的組件,主要是從以下4方面進行考慮的。

同步粒度:
Nacos Sync 同步數據的時候是以服務爲維度, 比較容易做最終一致性處理, 同時可以提供保活的機制,滿足節點維持的場景。 數據庫通過 Binlog 同步的方式只能侷限於事務粒度, 而文件同步只能通過單個文件的粒度, 在服務同步這個維度並不是很合適。

可用性方面:
Nacos Sync 作爲一箇中間件,是以集羣方式進行的,傳統的數據庫和文件方式基本是單進程進行的,可用性方面可能不太滿足要求。

同步方式方面:
Nacos Sync 通過在服務粒度的全量寫入,滿足服務註冊和 DNS 這兩種場景, 不需要額外的事務消耗, 能保證最終一致即可。

環形同步:
我們國內有多個可獲的節點,希望它們之間的數據可以進行環形同步,每個節點之間是相互備份的,這時候用 Nacos Sync 的話,是支持的。雖然數據庫方面,比較經典的是主主同步,但如果同時對一個主件進行更新的話,每一個點進行協助是會有問題的,而且文件方面是不支持的。

Nacos Sync 和開源版本的不同
我們對 Nacos Sync 開源方案上做了幾處修改,以更好的適用於現在的場景:

第一,通過配置方式對任務進行分拆。因爲在實際應用場景裏面,因爲 Nacos Sync 的任務達一兩萬,單機很容易到達瓶頸,所以我們通過配置的方式將這些分片到多臺 Nacos Sync 機器上。

第二,通過事件合併和隊列控制的方式控制 Nacos 集羣的寫入量,以保證後端的穩定性。雖然下發事件一秒鐘只有一個,但在很多場景中,例如需要 K8s 或者 Taf 進行數據同步的時候,變化的頻率是非常高的,這時候通過事件合併,每個服務單獨進行一個寫入進程。這樣通過隊列控制的方式可以控制整個 Nacos 集羣的寫入量。

第三,添加了能支持從K8s 和 Taf 同步數據的功能。後期我們會將這個特性提交給 Nacos,讓更多的開發者使用。

核心組件設計 DNS - F
DNS - F是基於 CoreDNS 上開發的,我們擴展了以下 4 個組件:

Nacos 插件:查詢 Nacos 服務信息,監聽 Nacos 服務變化,並將服務轉化爲域名,實現以 DNS 協議爲基礎的服務發現;

Cache 插件:提供域名緩存服務;

Log 插件:將 DNS 解析日誌上報到日誌服務;

Proxy 插件:代理解析外部域名;

DNS - F 和開源版本的不同
第一,在日誌組件裏面將日誌上傳到自己的日誌服務。

第二,對緩存功能做了一個增強。一般的緩存功能可能根據 TTL 時間會過期,我們把這個過期時間給去掉了,直接令到緩存永遠不會過期,然後通過異步將這個緩存進行刷新。比如 TTL 可能快到到時間了,我們就會主動做一個查詢或者推送查詢,這樣,服務端或者公共 DNS 出現問題的時候,就不會影響到整體服務。

第三,增強了高可用的保障能力。包括進程監控、內部運營和外部運營的探測。另外,原來的開源版本用的是本機部署的方式,我們做成了集羣化的部署,解決了服務推送、服務負載均衡方面的問題。

高可用
接下來由我們團隊的李志鵬,分享一下虎牙在高可用方面的實踐。

周健同學跟大家介紹了項目的背景跟方案設計,我來和大家介紹一下具體的實踐和落地,實踐過程中的主要關注點是高可用。

全球化部署方案
虎牙在全球 DNS 秒級生效上的實踐

這是虎牙的一個全球化的部署方案,我們在全球部署了兩個大區,分別是國內和國外。這兩個大區是指定服務同步的,走的是專線,這樣可以保障同步的穩定性。在一個大區內我們又部署了多個接入點,例如在國內大區,我們部署了深圳和無錫兩個接入點,這兩個節點的數據是互相同步、互爲備份,保證在一個集羣掛掉下可以切換到另外一個集羣。

多個接入點的情況下,我們通過 HttpDNS 實現客戶端的就近接入。客戶端定期請求 HttpDNS,HttpDNS 能根據地域尋找就近接入點。如果接入點出現故障,我們就直接在HttpDNS 把這個節點給摘除,這樣客戶端就能快速地切換到另外一個接入點。

接下來講一下單個集羣下的部署方案。

虎牙在全球 DNS 秒級生效上的實踐

單個集羣部署了多個 Nacos 節點,並通過7層負載均衡的方式暴露給外面使用,並且提供了多個 VIP,滿足不同線路和區域的接入要求。同時,Nacos Sync 做了分片處理,將同步壓力分散到各個分片上,一個分片下我們又部署了多個 Nacos Sync 的節點,以保障多活和高可用。

線上演練
演練的場景是模擬一個單個集羣掛了和兩個集羣都掛了。

虎牙在全球 DNS 秒級生效上的實踐

從圖中可以看到,把深圳的流量切走之後,無錫的流量就漲上去了,然後再把無錫的流量切走,再關閉服務,這樣就可以看到兩邊的流量已經沒了。之後,再去恢復兩個集羣的流量,看一下整個切換過程中對服務的影響。

虎牙在全球 DNS 秒級生效上的實踐

首先看一下對寫入的影響,在單個集羣掛了的情況下,是沒有任何影響的。如果是兩個集羣都掛了,寫入就會失敗。可以看到,這個圖有一個波峯,這個波峯就是我們兩個集羣都掛了的情況下,寫入失敗延遲加大。

但是切換的整個過程對 DNS-F 是沒有任何影響的,延遲保持平穩。此外,在集羣重新上線前,我們需要做數據校驗,保證集羣之間元數據和實例數據的最終一致。

可用性級別方面,我們可以保障:

單集羣掛掉後不會有影響;
雙集羣掛掉後只會影響域名變更,不影響域名解析;
線上演練數據校驗機制
運行過程中,我們也要保證集羣間數據的一致性。我們通過全量校驗和增量校驗兩種手段去保證,全量校驗方式如下:

大區內部做10分鐘的全量校驗,保證大區內各個集羣數據的一致;
大區之間做2分鐘做一次全量校驗,保證大區之間被同步的服務的數據一致性。
增量校驗方式如下:
從其他數據源同步的數據,通過數據源的時間戳,做增量校驗;
基於API的寫入日誌,定期校驗寫入的內容是否已經全部同步。
DNF - S 高可用
關於 DNS - F 的高可用,我們主要做了以下5個點:

Agent 的健康狀態監測,包括進程存活和是否能正常解析;
緩存內部域名,並做持久化處理,保證 Nacos 集羣出現問題時不會影響內部域名的解析;
提供備用節點,保證在 DNS-F 掛了,或者是 DNS-F 需要升級的情況下,也不會影響到內部域名解析;
resolv.conf 配置檢查,發現127.0.0.1不在配置中會自動添加;
限制 Agent 的 CPU 的使用,避免對業務進程造成影響。
具體的實踐和落地
實踐一:數據庫域名改造
之前的數據庫是用 IP 方式接入的,在數據庫切換的時候,需要通知每個業務方修改配置,重啓服務,這樣就帶來一個問題:整個過程是不可控的,取決於業務方的響應速度,生效時間通常超過十分鐘。

虎牙在全球 DNS 秒級生效上的實踐

提升數據庫切換的關鍵點,第一個就是切換時不需要業務方參與,能在業務方無感知的情況下進行切換;第二個是實例變化能秒級推送到我們的應用,將應用快速切換到一個新的實例上。

虎牙在全球 DNS 秒級生效上的實踐

大家可以看一下這個圖,這是我們現在做的一個改造,圖中的 DMX 是虎牙內部的一個數據庫管理系統,思路就是把 DMX 和名字服務打通。DMX 會把數據庫實例信息以服務的形式註冊到名字服務,服務名就是域名。

實際應用過程中,通過這個域名去訪問數據庫,應用在訪問前首先會經過 DNS - F 去做域名的解析,解析的時候是從名字服務查詢實例信息,然後把實例的IP返回給應用。這樣,應用就能通過 IP 和我們的數據庫實例進行連接。

切換的時候,在 DMX 平臺修改域名對應的實例信息,並把變更推送到名字服務,名字服務再推送給 DNS-F,應用在下一次解析的時候就能拿到新的實例 IP,達到切換數據庫實例的目的。

這套方案落地後,虎牙的數據庫切換基本上在10秒鐘之內能夠完成。

實踐二:內部調用使用內部域名
虎牙部分內部系統之間調用是通過7層負載均衡,但是由於沒有內部 DNS,需要通過的公共的 LocalDNS 來解析,這就帶來一些問題:

問題一:擴縮容的時候要去修改 DNS 記錄,整個過程生效時間可能會超過10分鐘,故障的節點會影響業務較長的時間。

問題二:公共的 LocalDNS 智能解析不準確,比如無錫的機器可能會解析到深圳的一個接入點,影響接入質量。

問題三:不支持定製化的負載均衡策略,例如同機房、同大區優先的策略,通過公共 LocalDNS 是實現不了的。

如果想要提升內部服務調用質量,一是 DNS 記錄變更繞過 LocalDNS,把 DNS 的記錄變更直接推到 DNS-F。二是與內部系統打通,從 CMDB 等內部系統獲取機器信息,支持多種負載均衡策略。

虎牙在全球 DNS 秒級生效上的實踐

大家可以看一下上面的圖,這個改造和數據庫域名的改造思路是一樣的,最右上角有一個7層負載管理系統,我們把這個系統和名字服務打通,7層負載管理系統會把域名信息以服務形式註冊到名字服務,變更域名記錄時直接從7層負載管理系統推送到名字服務,名字服務再推送到 DNS-F,達到快速切換的目的。

如果域名配置了負載均衡策略,名字服務會從 CMDB 獲取機器、機房等信息,打標到域名的實例信息。然後,DNS-F 查詢名字服務時,會攜帶 ClientIp,名字服務根據 ClientIp 的CMDB 信息過濾實例列表,返回同機房的實例給 DNS-F,達到同機房優先的目的。

由此帶來的效果是:

第一,服務擴縮容能夠秒級完成,減少了故障時間。

第二,擴展了 DNS 的負載均衡策略,例如有些業務是需要在不同區域有不同的接入點的,而且不能跨區域調用,之前的 DNS 負載均衡策略是不能滿足這個需求的,但在改造之後,我們能根據 CMDB 信息去做同區域調度的負載均衡策略。

第三,業務在接入內部域名之後,延遲會有明顯的下降。上圖顯示的就是某個服務在接入到內部域名之後,延遲出現明顯的下降。

另一個落地的效果就是我們對主機上的域名解析的優化。因爲我們的 DNS - F 是部署在每臺主機上的,然後提供一個緩存的功能。帶來的效果就是:

平均解析延遲會從之前的200毫秒下降到現在的1毫秒;
虎牙在全球 DNS 秒級生效上的實踐
緩存命中率會從之前的90%上升到99.8%,90%是用 CoreDNS 原生的那個 Cache,99.8%是在這個 Cache 的組件下做了優化之後的效果;
解析失敗率是從之前的0.1%下降到0%;
這裏再總結一下項目落地的技術價值:

第一,提供了基於 DNS 服務發現的能力,消除異構系統之間互相調用的障礙。

第二,填補了沒有內部域名解析能力的空白。

第三,解決我們上面說的內部服務調用面臨的挑戰:延時大、解析不準、不支持多種負載均衡策略、故障牽引慢。

第四,優化外部域名的解析,屏蔽 LocalDNS 的故障。

落地規模是:DNS - F 覆蓋率100%,完成 Taf 和 Eureka 註冊中心的數據同步。

後續規劃
LocalDNS:

解決公共 DNS 節點位置影響域名解析準確性的問題;

解決內部使用公共 DNS 不穩定的問題;

優化內外網解析;

精準調度:

解決全球 DNS 節點生效慢的問題。

本文作者:

周健:GitHub ID @nanamikon,虎牙中間件團隊成員,2012年畢業於中山大學,主要負責名字和配置服務,以及虎牙 DNS 和微服務相關的工作。

李志鵬:GitHub ID @lzp0412,虎牙中間件團隊成員,主要負責 DNS,以及服務註冊與發現、服務治理、Service Mesh 等相關工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章