千億級HttpDNS服務是怎樣煉成的

鵝廠網事發表於2018-11-13


"鵝廠網事"由深圳市騰訊計算機系統有限公司技術工程事業群網路平臺部運營,我們希望與業界各位志同道合的夥伴交流切磋最新的網路、伺服器行業動態資訊,同時分享騰訊在網路與伺服器領域,規劃、運營、研發、服務等層面的實戰乾貨,期待與您的共同成長。

網路平臺部以構建敏捷、彈性、低成本的業界領先海量網際網路雲端計算服務平臺,為支撐騰訊公司業務持續發展,為業務建立競爭優勢、構建行業健康生態而持續貢獻價值!

千億級HttpDNS服務是怎樣煉成的

【前言】

千億級HttpDNS服務是怎樣煉成的

話說距離鵝廠的HttpDNS服務(【鵝廠網事】全域性精確流量排程新思路-HttpDNS服務詳解)推出已經快4年時間了。在這一千多天裡面,HttpDNS服務不僅成了cloudflare、google等各大雲廠商的標配服務,而且還在IETF成立了相應的工作組,RFC草案(DNS over Https)已經出到第14版了,離正式成為網際網路標準越來越近。而騰訊作為首家提供HttpDNS服務的雲服務商,日解析量在數月前就超過了一千億次,每秒峰值併發請求達到了百萬級別,為上千家企業的域名解析保駕護航。到底是什麼支撐著這海量的HttpDNS服務?本文將為你一一道來。

千億級HttpDNS服務是怎樣煉成的

一、 快、準、穩,無縫擴容的高可用架構

千億級HttpDNS服務是怎樣煉成的

騰訊HttpDNS服務作為億級使用者訪問網際網路的第一跳,優質的網路質量至關重要,故在HttpDNS服務的接入層,採取了對外BGP Anycast+對內OSPF的架構。當前在國內華南、華東、華北,以及東南亞、北美部署了多個節點,不僅與國內及海外數十餘家運營商建立了互聯來縮短使用者訪問的網路路徑,而且還對路由進行精細化調優,保證使用者訪問延遲降到最低。

千億級HttpDNS服務是怎樣煉成的

BGP Anycast的網路架構不僅實現了使用者訪問的低延遲,同時還保證了HttpDNS服務的高可用。該架構不僅實現了在單一地區節點全部發生故障的時候將使用者的訪問流量遷移到其餘服務正常的節點,而且能精細化到的單一出口網路發生故障時的流量遷移。比如華南節點的A運營商出口發生了故障,而其餘的B、C、D運營商並沒有發生故障,那麼透過騰訊的公網流量排程平臺即可單獨將華南節點的A運營商出口流量遷移到其餘節點,而其B、C、D運營商的流量繼續使用華南節點覆蓋,盡力保證在單運營商出口發生故障時對使用者訪問的影響降到最低,整個切換過程在分鐘級別的耗時內即可完成。而對於OSPF叢集內的單機故障,則實現了秒級切換。至於平行擴容,更是撒撒水啦,OSPF域裡面加機器不就完了麼?

千億級HttpDNS服務是怎樣煉成的

二、 容量不夠,機器來湊?

千億級HttpDNS服務是怎樣煉成的

要支援海量HttpDNS訪問自然很簡單的啦,一臺機器5w併發,20臺機器就100w併發,40臺機器就200w併發,哪裡容量不夠擴哪裡,so easy!全文完,謝謝大家觀看!


===========================

千億級HttpDNS服務是怎樣煉成的

不好意思走錯片場了,開個玩笑~問題真那麼簡單就好了,走OSPF叢集擴容的話,且不說IDC機房裡機位資源的問題。像HttpDNS服務這種每兩三個月請求量就翻一倍的服務,有能跑5w qps的機器來擴容自然美滋滋,但流量上來了能跑3w qps的機器也得頂上啊。5w qps的伺服器和3w qps的伺服器在同一個OSPF域裡面權重怎麼搞,難道還要去算ECMP路徑下的交換機埠不成? 

   

千億級HttpDNS服務是怎樣煉成的

為了解決最大化利用不同配置的伺服器資源和同IP不同業務分離部署的問題,我們需要一個高效能的4層負載均衡器。但LVS的那點效能根本就不夠用,而在2014年這個時間點,業界基於DPDK的4層負載均衡器又還沒誕生。萬(tan)般(xiao)無(feng)奈(sheng)之下,只能自己動手,擼了個轉發效能千把萬pps、支援按後端例項處理能力來設定權重分發流量的DPDK LD,解決了HttpDNS和public DNS服務分離部署以及最大化利用不同處理能力等例項來滿足突發流量等快速擴容問題。這下子問題總解決了吧?


千億級HttpDNS服務是怎樣煉成的

少年你太年輕了!上了DPDK LD只是解決了可以在資源池裡面撿非標裝置來擴容而已,但是後端的伺服器處理能力並沒有提升啊!你這100w的短連結併發請求用單機5w併發的機器去抗還是要20臺伺服器的算力啊!200w併發就是40臺伺服器啊!你搞了個4層的負載均衡在前面還多佔了倆機器+倆機架啊! 問題哪裡解決了啊摔!

 

千億級HttpDNS服務是怎樣煉成的

在一個寒風凜冽的早上,我拿著一份5塊錢的沙縣小吃在三和人才市場的大門下停住了腳步,陷入了深深的沉思:到底要怎麼樣才能提升HttpDNS服務的單機處理能力呢?

千億級HttpDNS服務是怎樣煉成的


千億級HttpDNS服務是怎樣煉成的

三、 提升效能,如何是好?

千億級HttpDNS服務是怎樣煉成的

(1)快取,又見快取

從本質上來將,HttpDNS服務就是一個透過http實現的遞迴域名解析服務,只要快取裡面沒有對應的解析記錄,那麼就必須根據DNS協議進行遞迴查詢。而一旦涉及到域名遞迴解析到話,這個耗時就沒譜了,什麼SRTT選路啦、公網遞迴質量啦,要是讓HttpDNS直接去遞迴的話,一條短連結的停等時間分分鐘教你做人。

所以要提升HttpDNS的處理能力,第一步就是要提升快取命中率,讓絕大部分的使用者請求都直接命中快取,減少httpdns遞迴處理耗時。所以HttpDNS的架構就成了這樣:

千億級HttpDNS服務是怎樣煉成的

● 當使用者的請求透過BGP Anycast網路來到了DPDK LD上之後,DPDK LD透過tunnel將請求轉發至一級快取;

● 一級快取收到請求後先查詢是否有本地快取,沒有的話就將請求按照RR級別的雜湊,轉發到二級快取;

● 二級快取收到請求後也是先找本地是否有快取,沒有的話就直接將請求轉發到後端遞迴節點。

● 透過一級快取by RR級別的遞迴雜湊+二級全域性快取的架構設計,HttpDNS服務達到了將近90%的快取命中率。

● 而在沒有命中快取的10%請求中,除去首次觸發遞迴的部分以外,其餘請求均透過75% TTL非同步觸發遞迴機制在使用者無感知下完成更新。

● 最終實現了在遵循權威DNS TTL設定的情況下,將絕大部分HttpDNS的請求直接透過一次查詢就獲取到最終結果。

 

(2)百萬級的http短連結之Linux協議棧篇

然而快取命中率的提高只是減少了域名遞迴解析對處理效能的影響,一次查詢就命中快取是不用卡遞迴了,但這百萬級別http短連結併發請求怎麼搞?堆機器是不可能的,這輩子都不可能堆機器。所以提升HttpDNS處理效能的第二步,就是要提升一級快取每個例項的http短連結處理能力。

不就是C10k嘛,有啥難的,先來個多程式併發連結模型:

 

千億級HttpDNS服務是怎樣煉成的

不同程式之間互不影響,不存在鎖的開銷,每個子程式從接收請求、處理、最後傳送請求實現一條龍服務。再把什麼親和性啊、連線重用啊、佇列啥的最佳化全部滿上,8w+ qps達成!

 

千億級HttpDNS服務是怎樣煉成的

美你個大頭鬼啊!幾百萬併發短連結你單機跑個8w+ qps,你自己算算要多少臺伺服器?

 

千億級HttpDNS服務是怎樣煉成的

 

(3)DPDK over TCP

既然傳統的Linux協議棧要再進一步提升http短連結的效能空間不大,要不就換個基於DPDK實現的TCP協議棧試試?理想是美好的,現實是骨感的。GSLB團隊關注過多個開源的DPDK專案(seastar、mTCP等),並基於Seastar框架開發了新架構的HttpDNS。但從實驗室環境驗證完畢灰度到現網後,問題不斷,技術研究一度停滯,直到騰訊雲DNSPod團隊開發的F-Stack專案進入了我們的視野。

F-Stack()是基於DPDK+FreeBSD協議棧的全使用者態的高效能run-to-completion模型網路接入開發包,提供了友好的網路API介面,上層應用只需要進行簡單的調整改造,即可利用DPDK大幅提升網路效能。

GSLB團隊基於F-Stack對HttpDNS服務進行了遷移改造,透過DPDK按每程式繫結一個網路卡佇列,DPDK從網路卡收包後input給freebsd的網路協議棧;應用程式透過建立socket,繫結所配置的IP及埠並監聽之,基於epoll從FreeBSD的協議棧收取對應的資料包,處理完成後再write到FreeBSD的協議棧,由其output給DPDK進行回包。最終實現了在24核心48執行緒的CPU+128G記憶體+10G 網路卡的情況下,將HttpDNS的單機效能提升到了40w qps,比起傳統的linux協議棧版本效能提升了500%!  

千億級HttpDNS服務是怎樣煉成的

然而即使單機效能有了大幅的提升,但這個框架還遠沒達到極限。透過觀察發現,在極限負載下,HttpDNS的伺服器上有部分CPU沒有被充分利用起來。經過排查分析發現是由於x540網路卡只有16個網路卡佇列,所以按上述框架就只能起16個處理程式,導致了CPU的出現了空閒。 針對這種情況,GSLB團隊進行了架構的最佳化,採用pipeline與run-to-completion結合的模式:一個程式收包,透過ring進行分發,多個處理程式從對應ring取包並處理、最後透過對應的網路卡佇列將應答包傳送出去,架構如下:


千億級HttpDNS服務是怎樣煉成的  

透過調整,在同等硬體配置下,HttpDNS的單機服務能力提升到了89w qps!從此公主和王子就過上了幸福美滿的生活,全文完。

=========================== 

千億級HttpDNS服務是怎樣煉成的  

然後現實又一次給我們打臉了,面對現網瘋漲的流量,F-stack HttpDNS在沒有達到極限效能的情況下就出現了丟包。問題到底出在哪裡?透過分析,我們發現了生產環境和測試環境流量的差別:

1) 生產環境峰值瞬時併發連線數是在測試環境的1000倍;

2) 生產環境中有大量因各種原因的不能完成三次握手的無效請求,大量消耗了CPU的處理資源;

3) 在面對真實的使用者請求時,F-stack HttpDNS的分包演算法存在不均勻的情況,導致會出現部分CPU跑滿,而其他CPU又比較空閒的情況。

為了解決這些問題,GSLB團隊採取了一系列的改進措施:

1) 因為F-Stack的epoll是kqueue模擬的,而kqueue通知accept事件時,有可能為多個FD的連線事件,因此需修改為迴圈accept,獲取產生此次通知事件的所有FD。

2) 增大配置引數kern.ncallout的值,減少callout_proccess函式的回撥次數。

3) 最佳化dispatch分包演算法,更均勻各個處理程式的業務處理。

而正當我們為解決了生產環境下在高負載時丟包的問題鬆了一口氣時,一場突如其來的瞬時流量暴漲又把我們推到了風口浪尖上。由於客戶的業務突發,HttpDNS伺服器單機在5秒之內收到了將近600w的syn包,進而觸發了服務瞬間不可用,導致該伺服器從叢集中被剔除。而由於該伺服器被剔除之後的流量又被分攤到了叢集內的其他HttpDNS伺服器,導致了其他伺服器也輪番被剔除,造成整個叢集在訪問量突發期間不停地被剔除、增加。最終只能依靠人為干預流量分配,才解決了問題。

從此次事件中可以看出,HttpDNS暴露了兩個設計上的問題:

1) 心跳包(監控包)與業務包採用相同的通道:

當業務包處理能力不足而阻塞時會導致心跳包處理超時,而引起DPDK LD的誤判。此時雖然部分請求可能會出現短暫超時,但伺服器本身並沒有出現故障,總體服務還是可用的。此時將伺服器剔除出叢集並不是一個正確的做法。

2) 系統過載保護設定不合理:

系統的過載保護是在應用層透過控制使用者併發連線數(FD)來實現,但此次事件中TCP三次握手的成功率低於正常情況,併發連線數未到達閥值,過載保護未能生效。

針對這兩個問題,我們做出瞭如下最佳化:

1) 心跳包與業務包通道的隔離。

在dispatch程式與業務處理程式間設計只儲存心跳包的ring, 用於進行心跳包的傳輸。

2) 實現更精確的過載保護。

從HttpDNS的架構中可以看出,當業務程式處理效能不足,引起業務包阻塞,那麼dispatch程式向業務包ring push資料時會失敗,據此我們做了以下最佳化:

i. 發生此種情況時進行高負載告警。

ii. 高負載情況下,優先完成已請求包的業務處理,控制新進包的處理:

a) 若dispatch向某處理程式對應的ring push一個資料包失敗,進行計數為5,此後dispatch將後續接收到的需分發至此程式的sync包drop掉,計數值減一,直至計數值<=0,才重新分發此程式的sync包。

b) 若某程式的計數值大於某個閥值時,dispatch進行異常告警,併傳送信令包給業務處理程式,令其重啟。

千億級HttpDNS服務是怎樣煉成的

經此最佳化後,HttpDNS在過載情況下,各業務程式CPU使用率都接近100%,使用者請求包的丟包率及丟包持續時間下降了30%以上。而且最重要的是,過載情況下的業務恢復已全程實現了自動化,再也不需要人為進行干預!至此,從架構設計到實現最佳化,從概念驗證到現網運營,騰訊HttpDNS服務頂住了壓力,實現了以極低的成本,支撐了千億級的海量業務穩定運營。

千億級HttpDNS服務是怎樣煉成的

四、 明日之後

千億級HttpDNS服務是怎樣煉成的

HttpDNS服務的本意是為了解決特定場景下的域名解析服務的問題,但在不經意間卻開啟了一道通往通用軟體定義流量排程解決方案的大門,賦予了內容服務提供商、移動網際網路開發者對於使用者訪問的更便捷、更精細化的排程能力。名字服務是流量排程最優雅的解決方案,更為精細、智慧、簡單、通用HttpDNS 2.0全域性流量排程解決方案已然在路上,一切只是剛剛開始,敬請期待!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31558022/viewspace-2219748/,如需轉載,請註明出處,否則將追究法律責任。

相關文章