Background
In mobile environments, DNS resolution overhead adds significant latency to network requests. Local DNS resolution uses the User Datagram Protocol (UDP). This makes it prone to timeouts on mobile networks with high packet loss rates. In weak network conditions, DNS resolution can add hundreds of milliseconds of latency. This slows down business requests and degrades the user experience.
Solution
HTTPDNS solves traditional problems such as domain hijacking and inaccurate scheduling. It also offers developers a more flexible way to manage DNS. By applying effective HTTPDNS management policies on the client, you can achieve zero-latency DNS resolution and greatly improve network communication efficiency in weak network environments.
The main strategies for zero-latency DNS resolution include the following:
Build a client-side DNS cache
You can use a well-designed DNS cache to ensure that IP information for each network request is retrieved from memory. This greatly reduces DNS resolution overhead. You can create more advanced cache policies based on your business needs, such as caching results by ISP. This lets you reuse cached IP information for different ISP lines during a network transition and avoid the DNS resolution overhead caused by re-selecting a link after the network changes. You can also use local offline storage for IP addresses. When the client restarts, it can quickly read domain name IP information from local storage. This greatly improves the loading speed of your home page.
Pre-resolve hot spot domain names
During client startup, you can pre-resolve hot spot domain names to load them into the cache. When a business request occurs, the IP information for the target domain name is read directly from memory. This avoids the network overhead of traditional DNS.
Use a lazy update policy
The IP information for business domain names rarely changes. This is especially true within a single application session, where the resolved IP address is often the same. Therefore, you can use a DNS lazy update policy for fast resolution after the Time to Live (TTL) expires. With a lazy update policy, the client does not actively check the TTL of an IP address. When a business request needs to access a domain name, the client queries the memory cache and returns the IP address. If the IP address has expired, the client performs an asynchronous DNS resolution in the background and updates the cache. This policy ensures that all DNS resolutions are served from memory, which avoids the latency caused by network requests.
Demo example
The HTTPDNS Demo on GitHub provides examples for the Android software development kit (SDK) and the HTTPDNS API operation. This section uses the Android SDK example to demonstrate how to implement a zero-latency HTTPDNS service.
public class NetworkRequestUsingHttpDNS {
private static HttpDnsService httpdns;
// Enter your HTTPDNS account ID. You can obtain this information from the HTTPDNS console.
private static String accountID = "100000";
// Your hot spot domain names.
private static final String[] TEST_URL = {"http://www.aliyun.com", "http://www.taobao.com"};
public static void main(final Context ctx) {
try {
// Set the AccountID and initialize HTTPDNS.
httpdns = HttpDns.getService(accountID);
// DegradationFilter is used to customize the degradation logic.
// By implementing the shouldDegradeHttpDNS method, you can choose whether to degrade as needed.
DegradationFilter filter = new DegradationFilter() {
@Override
public boolean shouldDegradeHttpDNS(String hostName) {
// You can customize the degradation logic here. For example, do not use HTTPDNS to resolve www.taobao.com.
// For more information, see the HTTPDNS API documentation. If an intermediate HTTP proxy exists, degrade to Local DNS.
return hostName.equals("www.taobao.com") || detectIfProxyExist(ctx);
}
};
// Pass the filter to httpdns. During resolution, the shouldDegradeHttpDNS method is called back to determine whether to degrade.
httpdns.setDegradationFilter(filter);
// Set the list of domain names to pre-resolve. In a real-world application, run the pre-resolution operation in the app's startup function. Pre-resolution is an asynchronous behavior and does not block your startup process.
httpdns.setPreResolveHosts(new ArrayList<>(Arrays.asList("www.aliyun.com", "www.taobao.com")));
// Allow expired IPs to be returned. By allowing expired IPs to be returned and using the asynchronous query operation, you can implement the DNS lazy update policy.
httpdns.setExpiredIPEnabled(true);
// Send a network request.
String originalUrl = "http://www.aliyun.com";
URL url = new URL(originalUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Use the asynchronous operation to get the IP address. When the IP TTL expires, the lazy update policy lets you get the most recent DNS resolution result directly from memory. The HTTPDNS SDK automatically updates the resolution result for the domain name in the background.
ip = httpdns.getIpByHostAsync(url.getHost());
if (ip != null) {
// The IP address is obtained from HTTPDNS. Replace the URL and set the HOST header.
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();
}
}
/**
* Check whether a proxy is set for the system. For more information, see the HTTPDNS API documentation.
*/
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;
}
}If you use the HTTPDNS API operation, you can customize more efficient management logic on the client to meet your specific needs.