雲計算

“SRTT” DNS服務器選擇算法介紹

大家都知道BIND在作為遞歸服務器時在向權威DNS請求時會使用優選策略,不過這個優選策略目前沒有清晰的資料。小編查閱了一些公開的資料發現基本都是各種傳抄,沒有什麼清晰的說明。因此小編專門編寫此文來科普遞歸是如何進行優選的。本文以BIND9.8/BIND9.9/BIND9.11的代碼為基礎,並假定域名有多個質量不同的NS來進行計算。

BIND9.8及之前版本的SRTT策略

目前可以查詢到的一部分公開的資料都是基於BIND9.8版本的,小編仔細查閱了BIND9.8的源代碼後,判定這些公開資料的描述基本符合事實情況。小編針對BIND9.8的SRTT計算過程描述如下:

1、首先BIND在第一次計算SRTT時為所有的NS記錄一個初始化的值,賦值方法是:

isc_random_get(&r);
e->srtt = (r & 0x1f) + 1;
e->expires = 0;

註釋:這個值為隨機1-32us,由於這個值非常小遠小於正常的SRTT,因此可以認為在初始化的時候,所有的NS都會得到一個很小的近乎為零的SRTT,因此所有的NS都有機會去被第一次優選。

2、在所有的NS中選擇SRTT最小的一個NS服務器發起解析請求,如得到應答則記錄這次請求的RTT,並重新計算這個NS的SRTT,計算方法是:

new_srtt = (addr->entry->srtt / 10 * factor)+ (rtt / 10 * (10 - factor));

註釋:這裡的factor定義如下:

#define DNS_ADB_RTTADJDEFAULT           7       /*%< default scale */
#define DNS_ADB_RTTADJREPLACE           0       /*%< replace with our rtt */
#define DNS_ADB_RTTADJAGE               10      /*%< age this rtt */

因此,在正常收到應答的情況:

        factor = DNS_ADB_RTTADJDEFAULT;

所以在正常的請求中,factor的值為7,所以這個新的NS的SRTT計算方法如下,也就是說這次請求的RTT在新的SRTT值的計算中權重佔30%:old_srtt 0.7 + curr_rtt 0.3

3、在這次請求中計算了請求的NS的同時,還需要對其他的NS進行衰減計算,計算方法如下:

if (factor == DNS_ADB_RTTADJAGE)
     new_srtt = addr->entry->srtt * 98 / 100;

註釋:即所有的SRTT賦值為原來的98%

4、如果本次NS請求以失敗告終,即發出請求並沒有得到應答的情況,這裡就要對這個NS進行懲罰,計算方法如下:

INSIST(no_response);
     rtt = query->addrinfo->srtt + 200000;
     if (rtt > 10000000)
     rtt = 10000000;

註釋:直接給SRTT加上200ms,且SRTT最大值不能超過10s

5、1800s後,所有的SRTT清零,重複以上的計算
這個1800來自源碼的宏定義:

#define ADB_ENTRY_WINDOW        1800    /*%< seconds */

BIND9.9及以後版本的SRTT策略

1、首先BIND在第一次計算SRTT時為所有的NS記錄一個初始化的值,用樣的賦值方法,隨機1-32us。

2、在所有的NS中選擇SRTT最小的一個NS服務器發起解析請求,如得到應答則記錄這次請求的RTT,並重新計算這個NS的SRTT,同樣的計算方法old_srtt 0.7 + curr_rtt 0.3

3、其他NS的計算方法如下:

if (addr->entry->lastage != now) {
       new_srtt = addr->entry->srtt;
       new_srtt <<= 9;
       new_srtt -= addr->entry->srtt;
       new_srtt >>= 9;
       addr->entry->lastage = now;

註釋:大概值為“SRTT = ((SRTT<<9)-SRTT)>>9”,即賦值為原來的SRTT的511/512,大概99.8%,這是BIND9.9和之前版本在計算SRTT中的一個最重要的差別

5、如果本次NS請求以失敗告終,則懲罰方式如下:

INSIST(no_response);
rtt = query->addrinfo->srtt + 200000;
if (rtt > MAX_SINGLE_QUERY_TIMEOUT_US)
       rtt = MAX_SINGLE_QUERY_TIMEOUT_US;

註釋:這裡MAX_SINGLE_QUERY_TIMEOUT_US為宏定義,定義為

#define MAX_SINGLE_QUERY_TIMEOUT 9U
#define MAX_SINGLE_QUERY_TIMEOUT_US (MAX_SINGLE_QUERY_TIMEOUT*US_PER_SEC)

共9s,也就是SRTT的最大值降低了1s。值得說明的是,在BIND9.11中,這裡的懲罰邏輯又有了變化,計算方法如下:

INSIST(no_response);
isc_random_get(&value);
if (query->addrinfo->srtt > 800000)
       mask = 0x3fff;
else if (query->addrinfo->srtt > 400000)
       mask = 0x7fff;
else if (query->addrinfo->srtt > 200000)
       mask = 0xffff;
else if (query->addrinfo->srtt > 100000)
       mask = 0x1ffff;
else if (query->addrinfo->srtt > 50000)
       mask = 0x3ffff;
else if (query->addrinfo->srtt > 25000)
       mask = 0x7ffff;
else
       mask = 0xfffff;
……
rtt = query->addrinfo->srtt + (value & mask);

註釋:這裡面根據當前SRTT值的不同,重新定義了一個隨機數,而且是如果當前值的SRTT越小則懲罰的度量越大。

5、同樣的1800s後,所有的SRTT清零,重複以上的計算SRTT策略&DNS解析質量。所以BIND的SRTT整個過程如下:
image

SRTT從設計上來說即兼顧了DNS異常依賴的優選以及容災措施,在所有NS的存活的情況下能夠保持絕大部分的遞歸請求可以優選最好的NS,同時在個別NS掛掉的情況下又能容災切換至其他的NS。同時,根據BIND版本演進中的衰減/懲罰機制變化來看, BIND在保障容災的前提下儘可能更加選擇優選(衰減策略從原來BIND9.8版本的98%變更至BIND9.9版本的99.8%),因此對於被優選NS的質量也提出了更高要求。在此小編假設一種場景,對於BIND9.11版本的遞歸來講如果一直優選的那個NS因為異常原因發生了丟包從而被遞歸懲罰,將使用更長的時間和次數來為這個NS進行衰減,從而有更長的時間/更多的遞歸次數不能被優選(比如一個原本20ms的NS因為一次丟包導致SRTT增加至220ms,那麼需要2300次的衰減/或者等1800s過期才能使SRTT重新恢復至20ms),這對於遞歸的性能有本質上的影響。

因此,在衡量權威服務器本身性能的同時,是否擁有高質量的網絡/是否擁有低丟包率的權威軟硬件服務,也是重要的考量指標。在這裡小編需要指出,阿里雲在DNS這種互聯網基礎協議上持續進行基礎設施的投入,使得雲解析擁有全球高質量的BGP網絡和自研的高性能DNS,幾乎將雲解析權威的丟包率降低為零,從而實現了更高質量的遞歸解析性能。

Leave a Reply

Your email address will not be published. Required fields are marked *