閱讀663 返回首頁    go 英雄聯盟


如何利用HTTPDNS降低DNS解析開銷__最佳實踐_HTTPDNS-阿裏雲

1. 背景說明

移動場景下DNS的解析開銷是整個網絡請求延遲中不可忽視的一部分。一方麵基於UDP的localDNS解析在高丟包率的移動網絡環境下更容易出現解析超時的問題,另一方麵在弱網環境下DNS解析所引入的動輒數百毫秒的網絡延遲也大幅加重了整個業務請求的負擔,直接影響用戶的終極體驗。

2. 解決方案

HTTPDNS在解決了傳統域名劫持以及調度精確性的問題的同時,也提供了開發者更靈活的DNS管理方式。通過在客戶端合理地應用HTTPDNS管理策略,我們甚至能夠做到DNS解析0延遲,大幅提升弱網環境下的網絡通訊效率。

DNS解析0延遲的主要思路包括:

  • 構建客戶端DNS緩存;

通過合理的DNS緩存,我們確保每次網絡交互的DNS解析都是從內存中獲取IP信息,從而大幅降低DNS解析開銷。根據業務的不同,我們可以製訂更豐富的緩存策略,如根據運營商緩存,可以在網絡切換的場景下複用已緩存的不同運營商線路的域名IP信息,避免網絡切換後進行鏈路重選擇引入的DNS網絡解析開銷。另外,我們還可以引入IP本地化離線存儲,在客戶端重啟時快速從本地讀取域名IP信息,大幅提升首頁載入效率。

  • 熱點域名預解析;

在客戶端啟動過程中,我們可以通過熱點域名的預解析完成熱點域名的緩存載入。當真正的業務請求發生時,直接由內存中讀取目標域名的IP信息,避免傳統DNS的網絡開銷。

  • 懶更新策略;

絕大多數場景下業務域名的IP信息變更並不頻繁,特別是在單次APP的使用周期內,域名解析獲取的IP往往是相同的(特殊業務場景除外)。因此我們可以利用DNS懶更新策略來實現TTL過期後的DNS快速解析。所謂DNS懶更新策略即客戶端不主動探測域名對應IP的TTL時間,當業務請求需要訪問某個業務域名時,查詢內存緩存並返回該業務域名對應的IP解析結果。如果IP解析結果的TTL已過期,則在後台進行異步DNS網絡解析與緩存結果更新。通過上述策略,用戶的所有DNS解析都在與內存交互,避免了網絡交互引入的延遲。

2.1 Demo示例

我們在HTTPDNS Demo github中提供了Android/iOS SDK以及HTTPDNS API接口的使用例程,這裏我們通過使用Android SDK的例程演示如何實現0延遲的HTTPDNS服務。

public class NetworkRequestUsingHttpDNS {

    private static HttpDnsService httpdns;
    // 填入您的HTTPDNS accoutID信息,您可以從HTTPDNS控製台獲取該信息
    private static String accountID = "100000";
    // 您的熱點域名
    private static final String[] TEST_URL = {"https://www.aliyun.com", "https://www.taobao.com"};

    public static void main(final Context ctx) {
        try {
            // 設置APP Context和Account ID,並初始化HTTPDNS
            httpdns = HttpDns.getService(ctx, accountID);
            // DegradationFilter用於自定義降級邏輯
            // 通過實現shouldDegradeHttpDNS方法,可以根據需要,選擇是否降級
            DegradationFilter filter = new DegradationFilter() {
                @Override
                public boolean shouldDegradeHttpDNS(String hostName) {
                    // 此處可以自定義降級邏輯,例如www.taobao.com不使用HttpDNS解析
                    // 參照HttpDNS API文檔,當存在中間HTTP代理時,應選擇降級,使用Local DNS
                    return hostName.equals("www.taobao.com") || detectIfProxyExist(ctx);
                }
            };
            // 將filter傳進httpdns,解析時會回調shouldDegradeHttpDNS方法,判斷是否降級
            httpdns.setDegradationFilter(filter);
            // 設置預解析域名列表,真正使用時,建議您將預解析操作放在APP啟動函數中執行。預解析操作為異步行為,不會阻塞您的啟動流程
            httpdns.setPreResolveHosts(new ArrayList<>(Arrays.asList("www.aliyun.com", "www.taobao.com")));
            // 允許返回過期的IP,通過設置允許返回過期的IP,配合異步查詢接口,我們可以實現DNS懶更新策略
            httpdns.setExpiredIPEnabled(true);

            // 發送網絡請求
            String originalUrl = "https://www.aliyun.com";
            URL url = new URL(originalUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 異步接口獲取IP,當IP TTL過期時,由於采用DNS懶更新策略,我們可以直接從內存獲得最近的DNS解析結果,同時HTTPDNS SDK在後台自動更新對應域名的解析結果
            ip = httpdns.getIpByHostAsync(url.getHost());
            if (ip != null) {
                // 通過HTTPDNS獲取IP成功,進行URL替換和HOST頭設置
                Log.d("HTTPDNS Demo", "Get IP: " + ip + " for host: " + url.getHost() + " from HTTPDNS successfully!");
                String newUrl = originalUrl.replaceFirst(url.getHost(), ip);
                conn = (HttpURLConnection) new URL(newUrl).openConnection();
            }
            DataInputStream dis = new DataInputStream(conn.getInputStream());
            int len;
            byte[] buff = new byte[4096];
            StringBuilder response = new StringBuilder();
            while ((len = dis.read(buff)) != -1) {
                response.append(new String(buff, 0, len));
            }
            Log.e("HTTPDNS Demo", "Response: " + response.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 檢測係統是否已經設置代理,請參考HttpDNS API文檔。
     */
    public static boolean detectIfProxyExist(Context ctx) {
        boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
        String proxyHost;
        int proxyPort;
        if (IS_ICS_OR_LATER) {
            proxyHost = System.getProperty("http.proxyHost");
            String port = System.getProperty("http.proxyPort");
            proxyPort = Integer.parseInt(port != null ? port : "-1");
        } else {
            proxyHost = android.net.Proxy.getHost(ctx);
            proxyPort = android.net.Proxy.getPort(ctx);
        }
        return proxyHost != null && proxyPort != -1;
    }
}

對於使用HTTPDNS API接口的開發者,您可以在客戶端自己定製更高效,並且符合您需求的HTTPDNS管理邏輯。

最後更新:2016-11-23 16:04:07

  上一篇:go HTTPS業務場景解決方案__最佳實踐_HTTPDNS-阿裏雲
  下一篇:go Webview/H5場景下如何使用HTTPDNS進行域名解析__最佳實踐_HTTPDNS-阿裏雲