問題描述:某些地區(qū)性客戶反應應用更新無法下載問題
排查原因:用戶使用自帶瀏覽器打開下載地址(無法下載)(瀏覽器打不開說明不是應用問題)
協(xié)同運維同學和客戶溝通測試 結果 再用戶所在地我們域名DNS被劫持導致域名DNS解析時找不到對應對的ip
臨時方案: 先發(fā)一個新域名的下載地址給客戶 因為域名比較新所以沒有被劫持 可以下載
app端:添加容錯 在使用舊域名無法下載的時候,使用新域名下載
這樣就app的下載功能就可以正常使用,但是這只是一個臨時解決方案,要是新舊域名都被劫持了怎么辦了
所以我們還是需要找最終解決方案
在解決之前 我們首先要了解下什么是DNS
1.1什么是DNS
DNS(Domain Name System,域名系統(tǒng)),DNS 服務用于在網絡請求時,將域名轉為 IP 地址。能夠使用戶更方便的訪問互聯(lián)網,而不用去記住能夠被機器直接讀取的 IP 數(shù)串。
DNS的基一原理如下圖所示:

1.2 DNS 域名系統(tǒng)結構

如上圖所示,典型DNS域名系統(tǒng)的結構如下:
1)Root 域名:DNS 域名使用時,規(guī)定由尾部句號來指定名稱位于根或更高級別的域層次結構;
2)Top Level 頂級域名:用來指示某個國家、地區(qū)或組織使用的名稱的類型名稱。如 .net;
3)Second Level 域名:個人或組織在 Internet 上使用的注冊名稱。如 52im.net;
4)Third Level 域名:已注冊的二級域名派生的域名。如 docs.52im.net。
1.3 DNS 解析過程

<meta charset="utf-8">
如上圖所示,這是一個典型的域名解析過程:
1)瀏覽器中輸入 www.baidu.com,發(fā)出解析請求;
2)本機的域名解析器 resolver 程序查詢本地緩存和 host 文件中是否為域名的映射關系,如果有則調用這個 IP 地址映射,完成解析;
3)如果 hosts 與本地解析器緩存都沒有相應的網址映射關系,則本地解析器會向 TCP/IP 參數(shù)中設置的首選 DNS 服務器(我們叫它 Local DNS 服務器)發(fā)起一個遞歸的查詢請求;
4)服務器收到查詢時,如果要查詢的域名由本機負責解析,則返回解析結果給客戶機,完成域名解析,此解析具有權威性。如果要查詢的域名,不由 Local DNS 服務器解析,但該服務器已緩存了此網址映射關系,則調用這個 IP 地址映射,完成域名解析,此解析不具有權威性;
5)如果 Local DNS 服務器本地區(qū)域文件與緩存解析都失效,則根據 Local DNS 服務器的設置(是否遞歸)進行查詢,如果未用開啟模式,Local DNS 就把請求發(fā)至13臺 Root DNS。如果用的是遞歸模式,此 DNS 服務器就會把請求轉發(fā)至上一級 DNS 服務器,由上一級服務器進行解析,上一級服務器如果不能解析,或找根 DNS 或把轉請求轉至上上級,以此循環(huán);
6)Root DNS 服務器收到請求后會判斷這個域名是誰來授權管理,并會返回一個負責該頂級域名服務器的一個 IP;
7)Local DNS 服務器收到 IP 信息后,將會聯(lián)系負責 .net 域的這臺服務器;
8)負責 .com 域的服務器收到請求后,如果自己無法解析,它就會找一個管理 .net 域的下一級 DNS 服務器地址給本地 DNS 服務器;
9)當 Local DNS 服務器收到這個地址后,就會找 百度 域服務器,10、11重復上面的動作,進行查詢;
10)最后 www.baidu.com 返回需要解析的域名的 IP 地址給 Local DNS 服務器;
11)Local DNS 服務器緩存這個解析結果(同時也會緩存,6、8、10返回的結果);
12)Local DNS 服務器同時將結果返回給本機域名解析器;
13)本機緩存解析結果;
14)本機解析器將結果返回給瀏覽器;
15)瀏覽器通過返回的 IP 地址發(fā)起請求。
1.4國內移動端網絡所面臨的各種DNS雜癥
總結下來,DNS的這些咋整主要的帶來了三類問題:
1)LocalDNS劫持;
2)平均訪問延遲下降;
3)用戶連接失敗率下降。
LocalDNS劫持: 由于HttpDNS是通過ip直接請求http獲取服務器A記錄地址,不存在向本地運營商詢問domain解析過程,所以從根本避免了劫持問題。 (對于http內容tcp/ip層劫持,可以使用驗證因子或者數(shù)據加密等方式來保證傳輸數(shù)據的可信度)
平均訪問延遲下降: 由于是ip直接訪問省掉了一次domain解析過程,(即使系統(tǒng)有緩存速度也會稍快一些‘毫秒級’)通過智能算法排序后找到最快節(jié)點進行訪問。
用戶連接失敗率下降: 通過算法降低以往失敗率過高的服務器排序,通過時間近期訪問過的數(shù)據提高服務器排序,通過歷史訪問成功記錄提高服務器排序。如果ip(a)訪問錯誤,在下一次返回ip(b)或者ip(c) 排序后的記錄。
2問題根源
要解決問題,我們得先得了解下現(xiàn)在國內各ISP的LocalDNS的基本情況。國內運營商LocalDNS造成的用戶訪問異??梢詺w為下三類:
2.1 域名緩存
域名緩存很好理解,就是LocalDNS緩存了騰訊的域名的解析結果,不向騰訊權威DNS發(fā)起遞歸。

為何LocalDNS要把域名解析結果進行緩存呢?原因有以下幾個:
(1)保證用戶訪問流量在本網內消化:國內的各互聯(lián)網接入運營商的帶寬資源、網間結算費用、IDC機房分布、網內ICP資源分布等存在較大差異。為了保證網內用戶的訪問質量,同時減少跨網結算,運營商在網內搭建了內容緩存服務器,通過把域名強行指向內容緩存服務器的IP地址,就實現(xiàn)了把本地本網流量完全留在了本地的目的。
(2)推送廣告:有部分LocalDNS會把部分域名解析結果的所指向的內容緩存,并替換成第三方廣告聯(lián)盟的廣告。
這種類型的行為就是我們常說的域名緩存,域名緩存會導致用戶產生以下的訪問異常:
A、僅對80端口的http服務做了緩存,如果域名是通過https協(xié)議或其它端口提供服務的,用戶訪問就會出現(xiàn)失敗。比如支付服務、游戲通過指定端口連接connect server服務等。
B、緩存服務器的運維水平參差不齊,時有出現(xiàn)緩存服務器故障導致用戶訪問異常的問題。
2.2、解析轉發(fā):
除了域名緩存以外,運營商的LocalDNS還存在解析轉發(fā)的現(xiàn)象。解析轉發(fā)是指運營商自身不進行域名遞歸解析,而是把域名解析請求轉發(fā)到其它運營商的遞歸DNS上的行為。
正常的LocalDNS遞歸解析過程是這樣的

而部分小運營商為了節(jié)省資源,就直接將解析請求轉發(fā)到了其它運營的遞歸LocalDNS上去了:

這樣的直接后果就是騰訊權威DNS收到的域名解析請求的來源IP就成了其它運營商的IP,最終導致用戶流量被導向了錯誤的IDC,用戶訪問變慢。
2.3 LocalDNS遞歸出口NAT
LocalDNS遞歸出口NAT指的是運營商的LocalDNS按照標準的DNS協(xié)議進行遞歸,但是因為在網絡上存在多出口且配置了目標路由NAT,結果導致LocalDNS最終進行遞歸解析的時候的出口IP就有概率不為本網的IP地址。
如下圖所示:

這樣的直接后果就是GSLB DNS收到的域名解析請求的來源IP還是成了其它運營商的IP,最終導致用戶流量被導向了錯誤的IDC,用戶訪問變慢。
3、必須著手解決這些問題,但傳統(tǒng)解決方案問題太多
運營商的LocalDNS解析域名異常,給對用戶訪問騰訊互聯(lián)網業(yè)務的體驗造成了非常大的損害。
那么以前,我們是如何處理這些域名解析異常的問題的呢?
1)實時監(jiān)控+商務推動:
這種方案是目前騰訊的運營團隊一直在使用的方案。這種方案就是周期比較長,畢竟通過行政手段來推動運營商來解決這個問題是比較耗時的。另外我們通過大數(shù)據分析,得出的結論是Top 3的問題用戶均為移動互聯(lián)網用戶。對于這部分用戶,我們有什么技術手段可以解決以上的問題呢?
2)繞過自動分配DNS,使用114dns或Google public DNS:
這個方案看上去很美好,114dns是國內最大的中立緩存DNS,而Google又是秉承不作惡理念的互聯(lián)網工程帝國巨鱷,而且騰訊的權威DNS又支持edns-client-subnet功能,能直接識別使用Google publicDNS解析騰訊域名的用戶的IP地址,不會出現(xiàn)流量調度失效。
但是問題來了:
a. 如何在用戶側構造域名請求:對于PC端的客戶端來說,構造一個標準的DNS請求包并不算什么難事。但在移動端要向一個指定的LocalDNS上發(fā)送標準的DNS請求包,而且要兼容各種iOS和android的版本的話,技術上是可行的,只是兼容的成本會很高;
b. 推動用戶修改配置極高:如果要推動用戶手動修改PC的DNS配置的話,在PC端和手機客戶端的WiFI下面還算勉強可行。但是要用戶修改在移動互聯(lián)網環(huán)境下的DNS配置,其難度不言而喻。
3)完全拋棄域名,自建connectcenter進行流量調度:
如果要采用這種這種方案的話,首先你就得要拿到一份準確的IP地址庫來判斷用戶的歸屬,然后再制定個協(xié)議搭個connect center來做調度,然后再對接入層做調度改造。這種方案和2種方案一樣,不是不能做,只是成本會比較高,尤其對于騰訊這種業(yè)務規(guī)模如此龐大的公司而言。
既然上面的這些傳統(tǒng)方案都存在那么多的問題,那有沒有一種調度精準、成本低廉、配置方便的基于域名的流量調度系統(tǒng)呢?
4、當前主流的解決方案:HttpDNS出現(xiàn)了
4.1 什么HttpDNS?
HTTPDNS 利用 HTTP 協(xié)議與 DNS 服務器交互,代替了傳統(tǒng)的基于 UDP 協(xié)議的 DNS 交互,繞開了運營商的 Local DNS,有效防止了域名劫持,提高域名解析效率。另外,由于 DNS 服務器端獲取的是真實客戶端 IP 而非 Local DNS 的 IP,能夠精確定位客戶端地理位置、運營商信息,從而有效改進調度精確性。
HTTPDNS的原理如下圖所示:

4.2 HttpDns 主要解決的問題
Local DNS 劫持:由于 HttpDns 是通過 IP 直接請求 HTTP 獲取服務器 A 記錄地址,不存在向本地運營商詢問 domain 解析過程,所以從根本避免了劫持問題。
平均訪問延遲下降:由于是 IP 直接訪問省掉了一次 domain 解析過程,通過智能算法排序后找到最快節(jié)點進行訪問。
用戶連接失敗率下降:通過算法降低以往失敗率過高的服務器排序,通過時間近期訪問過的數(shù)據提高服務器排序,通過歷史訪問成功記錄提高服務器排序。
4.3 騰訊的HttpDNS思路
經過努力,騰訊公司的GSLB 團隊推出的HttpDNS是為移動客戶端量身定做的基于Http協(xié)議和域名解析的流量調度解決方案,專治LocalDNS解析異常以及流量調度不準。
詳細介紹如下。
騰訊的HttpDNS基本原理:

HttpDNS的原理非常簡單,主要有兩步:
A、客戶端直接訪問HttpDNS接口,獲取業(yè)務在域名配置管理系統(tǒng)上配置的訪問延遲最優(yōu)的IP。(基于容災考慮,還是保留次選使用運營商LocalDNS解析域名的方式);
B、客戶端向獲取到的IP后就向直接往此IP發(fā)送業(yè)務協(xié)議請求。以Http請求為例,通過在header中指定host字段,向HttpDNS返回的IP發(fā)送標準的Http請求即可。
HttpDNS帶來的優(yōu)勢:
從原理上來講,HttpDNS只是將域名解析的協(xié)議由DNS協(xié)議換成了Http協(xié)議,并不復雜。
但是這一微小的轉換,卻帶來了無數(shù)的收益:
A、根治域名解析異常:由于繞過了運營商的LocalDNS,用戶解析域名的請求通過Http協(xié)議直接透傳到了騰訊的HttpDNS服務器IP上,用戶在客戶端的域名解析請求將不會遭受到域名解析異常的困擾;
B、調度精準:HttpDNS能直接獲取到用戶IP,通過結合騰訊自有專利技術生成的IP地址庫以及測速系統(tǒng),可以保證將用戶引導的訪問最快的IDC節(jié)點上;
C、實現(xiàn)成本低廉:接入HttpDNS的業(yè)務僅需要對客戶端接入層做少量改造,無需用戶手機進行root或越獄;而且由于Http協(xié)議請求構造非常簡單,兼容各版本的移動操作系統(tǒng)更不成問題;另外HttpDNS的后端配置完全復用現(xiàn)有權威DNS配置,管理成本也非常低??偠灾?,就是以最小的改造成本,解決了業(yè)務遭受域名解析異常的問題,并滿足業(yè)務精確流量調度的需求;
D、擴展性強:HttpDNS提供可靠的域名解析服務,業(yè)務可將自有調度邏輯與HttpDNS返回結果結合,實現(xiàn)更精細化的流量調度。比如指定版本的客戶端連接請求的IP地址,指定網絡類型的用戶連接指定的IP地址等。
當然各位可能會問:用戶將首選的域名解析方式切換到了HttpDNS,那么HttpDNS的高可用又是如何保證的呢?另外不同運營商的用戶訪問到同一個HttpDNS的服務IP,用戶的訪問延遲如何保證?
為了保證高可用及提升用戶體驗,HttpDNS通過接入了騰訊公網交換平臺的BGP Anycast網絡,與全國多個主流運營商建立了BGP互聯(lián),保證了這些運營商的用戶能夠快速地訪問到HttpDNS服務;另外HttpDNS在多個數(shù)據中心進行了部署,任意一個節(jié)點發(fā)生故障時均能無縫切換到備份節(jié)點,保證用戶解析正常。
接入效果及未來展望:
當前騰訊的HttpDNS方案已在騰訊內部接入了多個業(yè)務,覆蓋數(shù)億用戶,并已持續(xù)穩(wěn)定運行超過一年時間。而接入了HttpDNS的業(yè)務在用戶訪問體驗方面都有了非常大的提升。
以某個接入HttpDNS的業(yè)務為例,該業(yè)務僅通過接入HttpDNS,在未做任何其它優(yōu)化的情況下,用戶平均訪問延遲下降超過10%,訪問失敗率下降了超過五分之一,用戶訪問體驗的效果提升非常顯著。另外騰訊的HttpDNS服務除了在騰訊內部被廣泛使用以外,也受到了業(yè)務同行的肯定。國內最大的publicDNS服務商114dns在受到騰訊DNS的啟發(fā)下,也推出了HttpDNS服務。
在未來的日子里,騰訊GSLB團隊將會在騰訊內部進一步推廣HttpDNS服務,并將在實際業(yè)務的需求下對HttpDNS服務進行升級,如提供更為通用、安全、簡單的接入協(xié)議,進一步提升接入用戶的網絡訪問體驗等等。希望HttpDNS能為各位在解決域名解析異常及全局流量調度失效方面提供一個簡單、可行的思路。
5.對于現(xiàn)在現(xiàn)在最合適的解決法案
因為114和騰訊都有個免費的DNS服務所以我們可以用個第三方框架優(yōu)先使用本地的DNS解析配合使用騰訊和114的免費DNS服務
最終使用的三方框架
七牛的HTTPDNS https://github.com/qiniu/happy-dns-android
5.1接入方式
implementation 'com.qiniu:happy-dns:0.2.13'
5.2添加工具類
public class HttpDns implements Dns {
private DnsManager dnsManager;
public HttpDns() {
IResolver[] resolvers = new IResolver[3];
try {
// 添加三個httpDns
resolvers[0] = AndroidDnsServer.defaultResolver();//localDns
resolvers[1] = new Resolver(InetAddress.getByName("114.114.114.114"));//114 httpDns
resolvers[2] = new DnspodFree();// 119.29.29.29 騰訊免費httpDns
dnsManager = new DnsManager(NetworkInfo.normal, resolvers);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
@Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
if (dnsManager == null) //當構造失敗時使用默認解析方式
return Dns.SYSTEM.lookup(hostname);
try {
String[] ips = dnsManager.query(hostname); //獲取HttpDNS解析結果
if (ips == null || ips.length == 0) {
return Dns.SYSTEM.lookup(hostname);
}
List<InetAddress> result = new ArrayList<>();
for (String ip : ips) { //將ip地址數(shù)組轉換成所需要的對象列表
result.addAll(Arrays.asList(InetAddress.getAllByName(ip)));
}
return result;
} catch (IOException e) {
e.printStackTrace();
}
//當有異常發(fā)生時,使用默認解析
return Dns.SYSTEM.lookup(hostname);
}
}
5.3.因為現(xiàn)在所有項目都用的okhttp
okhttp添加配置
okHttpClient = builder
.dns(new HttpDns())
.build();
5.4.如何進行測試
使用模擬器修修改本地host文件把下載地址的域名指向一個不明ip 然后下載 (提示下載失?。?br>
然后添加httpDns下載成功
接入成功