基于twisted實現的智能dns系統:smartdns
smartdns 是 python 語言編寫,基于 twisted 框架實現的dns server,能夠支持針對不同的dns請求根據配置返回不同的解析結果。smartdns獲取dns請求的源IP或者客戶端IP(支持edns協議的請 求可以獲取客戶端IP),根據本地的靜態IP庫獲取請求IP的特性,包括所在的國家、省份、城市、ISP等,然后根據我們的調度配置返回解析結果。
smartdns的使用場景:
-
服務的多機房流量調度,比如電信流量調度到電信機房、聯通流量調度到聯通機房;
</li> -
用戶訪問控制,將用戶調度到離用戶最近或者鏈路質量最好的節點上。
</li> </ol>舉個簡單的例子,我們的一個站點test.test.com同時部署在電信和聯通兩個機房,該站點在電信機房的ip為1.1.1.1、在聯通機房的 ip為 2.2.2.2,就可以通過smartdns做到該站點域名解析時判斷源IP為電信的IP時返回1.1.1.1、判斷源IP為聯通的IP時返回 2.2.2.2,從而達到不同運營商機房流量調度的目的。
支持的功能
支持A、SOA、NS記錄的查詢,支持DNS forward功能
性能
在虛擬機2.4G CPU上能夠處理1000QPS查詢請求,打開debug日志后可以到800QPS。3-5臺dns server組成的集群已經能夠滿足大部分站點的需求。
目前我們正在實現和小流量測試go語言實現的smartdns,能夠達到3wQPS以上,后續測試穩定后會開源出來,大家敬請期待:)
原理
smartdns響應dns請求的處理流程如下:
IPPool類的初始化和該類中FindIP方法進行解析處理是smartdns中最關鍵的兩個要素,這兩個要素在下面詳細介紹。其他的特性比如繼 承twisted中dns相關類并重寫處理dns請求的方法、升級twisted代碼支持解析和處理edns請求等大家可以通過代碼了解。edns知識可 以猛戳這里:DNS support edns-client-subnet
IPPool初始化
ip.csv內容格式如下:
200000001, 200000010,中國,陜西,西安,電信
其中各個字段含義分別為
IP段起始,IP段截止,IP段所屬國家,IP段所屬省份,IP段所屬城市,IP段所屬ISP
a.yaml配置文件格式:
test.test.com: ttl: 3600 default: 5.5.5.5 2.2.2.2 中國,廣東,,聯通: 1.1.1.1 3.3.3.1 中國,廣東,,電信: 1.1.1.2 3.3.3.2
配置中地域信息的key包括四個字段,分別帶有不同的權重:
-
國家: 8
</li> -
省份: 4
</li> -
城市: 2
</li> -
運營商: 1
</li> </ul>初始化階段,會生成一個名為iphash的dict,具體數據結構如下圖:
其中,iphash的key為ip.csv每一條記錄的起始IP,value為一個list,list長度為6,list前5個字段分別為以該 key為起始IP記錄的IP段截止、IP段所屬國家、IP段所屬省份、IP段所屬城市、IP段所屬ISP,第六個字段是一個hash,key為 a.yaml里面配置的域名,value為長度為2的list,iphash[IP段起始][6][域名1][0]為域名1在該IP段的最優解 析,iphash[IP段起始][6][域名1][1]為該最優解析的總權值,該總權值暫時只做參考。
iphash初始化過程中最關鍵的是iphash[IP段起始][6][域名1]的最優解析的計算,最簡單直接的方式是直接遍歷域名1的所有調度配 置,挑選出滿足條件且總權值最高的解析,即為最優解析。這種方式記錄整個iphash的時間復雜度為O(xyz),x為ip.csv記錄數,y為域名總數 量,z為各個域名的調度配置數。為了優化啟動速度,優化了尋找最優解析的方法:事先將每個域名調度配置生成一顆樹,這棵樹是用dict模擬出來的,這樣需 要最優解的時候就不需要遍歷所有調度配置,而是最多檢索15次即可找到最優,即時間復雜度為O(15xy),具體實現參考IPPool的 LoadRecord和JoinIP兩個方法。
有了初始化后的iphash數據結構之后,每次請求處理的時候,只需要定位請求IP處在哪個IP段,找到IP段起始IP,然后從iphash中取出最優解析,取出最優解析的過程是O(1)的。具體流程如下:
代碼
github: https://github.com/xiaomi-sa/smartdns
安裝
依賴:
python 2.6或者2.7 Twisted 12.2.0 zope.interface 4.0.1
安裝:
git clone smartdns到本地路徑,進入script目錄,執行install_smartdns.sh即可將smartdns安裝在本地,同時python環境和相關的依賴都是使用virtualenv來進行管理,不會對系統環境造成影響。
啟動:
進入smartdns的bin路徑下,執行sh run_dns.sh即可啟動smartdns
測試
本地測試 dig test.test.com @127.0.0.1
或者將搭建的smartdns加到測試域名的ns中進行測試。
支持
mail: fangshaosen@xiaomi.com
github: jerryfang8
EDNS相關請參考:DNS support edns-client-subnet
</div>
https://github.com/xiaomi-sa/smartdns
-