標籤:

阿里DNS:NSCD-DNS緩存詳解

阿里DNS:NSCD-DNS緩存詳解

1 人贊了文章

前言

NSCD(name service cache daemon)是GLIBC關於網路庫的一個組件,服務基於glibc開發的各類網路服務,基本上來講我們能見到的一些編程語言和開發框架最終均會調用到glibc的網路解析的函數(如GETHOSTBYNAME or GETHOSTBYADDR等),因此絕大部分程序能夠使用NSCD提供的緩存服務。當然如果是應用端自己用socker編寫了一個網路client就無法使用NSCD提供的緩存服務,比如DNS領域常見的dig命令不會使用NSCD提供的緩存,相反ping得到的DNS解析結果將使用NSCD提供的緩存。

本質上NSCD不止為DNS提供緩存服務,同時可以為passwd/group/hosts等服務提供緩存,本文重點介紹的是DNS(hosts)範疇內的緩存,相關測試結果和代碼的對象對應的是glibc-2.17版本。

NSCD配置詳解

通過man小編可以清楚地看到nscd有如下核心配置(以下只涉及hosts的部分配置):

reload-count unlimited | number #注意下文會具體說明enable-cache hosts <yes|no> #Enables or disables the specified service cache. The default is no.positive-time-to-live hosts value #success緩存的響應時間,注意,下文會具體說明negative-time-to-live hosts value #非success緩存的響應時間,注意,下文會具體說明

關於緩存時間

首先是最重要的這2的配置:

positive-time-to-live hosts 20negative-time-to-live hosts 10

實際查看代碼發現配置positive-time-to-live hosts並沒有什麼用處,代碼中hstcache.c主流程中會直接讀取DNS報文中的TTL並賦值給需要計算的timeout

/* Compute the timeout time. */ dataset->head.ttl = ttl == INT32_MAX ? db->postimeout : ttl; timeout = dataset->head.timeout = t + dataset->head.ttl;

這說明NSCD的DNS緩存控制是以DNS應答的TTL為主,這個positive-time-to-live配置純屬打個醬油。之所以出現這種情況小編猜測,NSCD不止處理dns同時也處理passwd/group等,老版本的NSCD忽略了DNS存在TTL,直到某一個版本中把DNS的TTL給加入了。於是小編翻查了相關ChangeLog,查到如下說明,驗證了自己的猜想:

* nscd caches now all timeouts for DNS entries Implemented by Ulrich Drepper.

關於主動刷新

reload-count 5 默認值是5,代表SUCCESS的緩存在內存中會Reload 5次

reload的time是DNS應答TTL+CACHE_PRUNE_INTERVAL,reload過程中NSCD會主動發起DNS請求(非客戶端發起),如果期間發生解析結果變更會將結果主動更新至NSCD緩存。這裡的CACHE_PRUNE_INTERVAL來自於相關的宏定義:

#define CACHE_PRUNE_INTERVAL 15

關於非success域名的緩存

查看代碼發現對於非success域名的緩存,NSCD會讀取配置中的negative-time-to-live hosts,將緩存一個negative-time-to-live hosts+CACHE_PRUNE_INTERVAL的時間

dataset->head.ttl = ttl == INT32_MAX ? db->negtimeout : ttl; timeout = dataset->head.timeout = t + dataset->head.ttl;

關於緩存的RR輪詢

代碼中沒有找到關於Round-Robin的處理邏輯,所以小編猜測NSCD是直接緩存了GETHOSTBYNAME/GETHOSTBYADD的應答結果,如果存在多條RR的情況下,將只會讀取應答結果中的第一條結果作為函數的返回值。實際測試情況也確實如小編預料,多條RR在NSCD的緩存中並沒有RR輪詢的效果,直到下一次reload更新緩存結果。這裡可能導致域名原本的負載均衡機制失效。

關於CNAME+A的結果

GLIBC的GETHOSTBYNAME/GETHOSTBYADD返回的TTL中直接讀取的是A類型的TTL,代碼中並沒有針對CNAME的TTL做特殊處理,因此在有CNAME+A的級聯應答結果中,緩存的timeout將只會讀取對應的A記錄的TTL。

當DNS應答結果只有CNAME時,DNS請求將被判定為失敗,這時CNAME的TTL將不起作用,緩存的時間將遵循非success域名的timeout計算。

return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);

總結

小編從總體上來講,使用nscd對於提升域名解析性能、降低DNS並發數量,對於一部分缺乏DNS緩存的開發框架有輔助作用,但是其也存在明顯的缺點:

1)多條RR的情況下失去輪詢功能,導致緩存周期內單機的負載均衡失效

2)域名變更生效可能持續一個TTL+15s,對於一部分講究變更快速生效的域名而言有一定的變更生效延誤

3)對於一部分異常導致解析錯誤的域名,有可能被NSCD緩存導致一段時間內解析都異常

因此,小編建議針對negative-time-to-live的配置可以直接設置為:

negative-time-to-live hosts 0

推薦閱讀:

Spring緩存穿透問題修復
Ehcache緩存配置和基本使用
如何利用Webp和http緩存節省30%的網路流量

TAG:DNS | 緩存 |