im美图应用移动域名系统优化实践:HTTPS请求时间减少近一半

时间:2020-10-20

仿微信



 1.介绍

 在移动互联网时代,应用制造商之间的竞争非常激烈,良好的用户体验必须优先考虑。美图产品以其高价值而闻名,并且非常重视产品的用户体验。从技术角度来看,域名系统优化是客户体验优化中的一个关键环节。如何减少域名系统的耗时以及如何减少域名劫持都是每个人都需要关注的研发问题。

 本文介绍了米托APP在移动终端域名系统优化中的实践(主要针对HTTPS协议)。文章内容全面,从域名系统的问题和原则到最终的优化效果,值得学习和借鉴。

 另外:如果您想详细了解移动域名系统的各种杂病和主流解决方案,建议您阅读《移动域名系统中域名劫持等杂病的综合理解:原理、根源、HttpDNS解决方案等》。

 2.相关文章

 移动弱网络和域名系统信息:

 第1卷:协议-第14章域名系统

 全面了解移动域名系统域名劫持及其他各种疾病:原理、根源、HttpDNS解决方案等。

 “百度应用移动网络深度优化实践分享(一):域名系统优化”

 现代移动网络短连接优化方法综述:请求速度、弱网络适应和安全保障

 “移动即时消息开发人员必须阅读(1):易于理解,理解移动网络的“弱”和“慢”

 移动即时消息开发者必须阅读(2):历史上最全面的移动弱网络优化方法总结

 基本知识数据:

 网络编程中的懒人介绍(7):用简单的方式理解HTTP协议

 脑残网络编程导论(3):对超文本传输协议的一些必要知识

 未知网络编程(8):从数据传输层深度解密HTTP

 理解HTTP协议从HTTP/0.9到HTTP/2的历史演变和设计思想;

 网络套接字的详细说明(HTTP和网络套接字的关系(第一部分)

 网络套接字的详细说明(HTTP和网络套接字的关系(第二部分)

 可能会影响你的面试:你知道在一个TCP连接上可以发起多少个HTTP请求吗?》

 HTTPS基本信息:

 “理解HTTPS在一分钟内解决了什么”

 “即时通讯安全(七):如果你这样理解HTTPS,一篇文章就足够了”

 即时消息安全(8):你知道HTTPS是使用对称加密还是非对称加密吗?》

 "阅读HTTPS:加密原理,安全逻辑,数字证书等."

 3.内容概述

 米托应用的移动域名系统优化实践:HTTPS请求时间减少了近一半_1

 在域名服务作用于网络连接之前,它会将域名解析为一个用于后续连接过程的IP地址(有关详细信息,请参阅:详细TCP/IP第1卷:协议-第14章域名系统)。

 当查询域名系统时,它会先在本地缓存中找到它。如果它不存在或者记录过期,它将继续向域名系统服务器发送递归查询,域名系统服务器通常是运营商的域名系统服务器。

 在这个过程中,会出现一些无法控制的问题。

 米托的移动产品将面临诸如域名系统劫持和实际用户环境的耗时波动等问题(参见:对移动终端中域名系统域名劫持等各种疾病的全面了解:原理、根本原因、HttpDNS解决方案等。)。DNS链接中的这些不稳定因素导致后续的网络请求被劫持或直接失败,对产品的用户体验产生不良影响。

 因此,我们优化了移动产品的域名解析,并制作了相应的软件开发工具包。在这个过程中,我们参考了行业内的主流方案,也做了一些实际的思考。

 以下内容将主要通过安卓平台来解释。

 4、本地域名系统与HTTP域名系统

 在长期实践中,互联网公司发现本地域名存在以下问题:

 1)域名缓存:运营商域名系统缓存域名解析结果,并将用户引导至网内缓存服务器;

 2)解析和转发&出口NAT:运营商DNS转发查询请求或出口NAT导致流量调度策略无效。

 什么是本地域名?一般来说,本地域名是指本地互联网服务提供商的域名:

 米托应用移动域名系统优化实践:HTTPS请求时间减少近一半_2.jpg

 ▲图中的“本地域名服务器”是本地域名系统

 为了解决本地域名系统的这些问题,业界也催生了HTTP域名系统的概念(注意:如果你不知道本地域名系统和HTTP域名系统的概念,请阅读“充分理解移动域名系统域名劫持的各种疾病:原理、根源、HttpDNS解决方案等”)。

 HTTP域名系统的基本原理如下:

 最初,用户向运营商的域名解析服务器发起UDP报文进行域名解析,但在HTTP域名解析下,我们修改为用户直接向HTTP网络服务器发起HTTP请求,并带有要查询的域名和本地IP地址,该HTTP网络将在域名解析后返回IP地址。

 例如,DNSPod的实现原理如下:

 米托应用的移动域名系统优化实践:HTTPS请求时间减少了近一半_ 4.jpeg。

 与本地域名相比,HTTP域名具有以下优势:

 1)解决域名解析异常:绕过运营商的域名解析系统,向具有域名解析功能的网络服务器发起查询;

 2)精确调度:HTTP DNS可以直接获取用户的IP地址,从而实现精确分流;

 3)扩展性强:基于HTTP协议,可以实现更强大的功能扩展。

 那么,我们应该直接通过HTTP域名系统吗?

 5.探索米托应用的域名系统优化策略

 与本地域名相比,HTTP域名有一些优势,但HTTP域名本身存在一些成本问题。

 美图的产品线非常丰富,涉及广泛的域名。为了适应每个产品的实际场景,我们在实践中设计了更加灵活的策略控制。

 首先,在政策方面,我们没有完全放弃本地域名。

 一个应用程序涉及到很多域名,所以我们可以从策略的角度来配置它的核心应用程序接口域名,使其通过HTTP域名解析系统,但是我们仍然希望它首先通过本地域名解析系统来处理非核心请求,然后在异常情况下升级到HTTP域名解析系统。

 那么如何判断本地域名的异常情况呢?

 我们选择了几个指标来衡量域名系统服务器的质量:

 1)1)IP记录的TTL时间:当发生DNS劫持时,返回的TTL可能有一个很大的值;

 2)解析耗时:如果解析一个域名服务器的耗时不理想,那么它就不是我们想要的;

 3)返回IP的连通性:测试返回IP的质量。如果连接条件不好,就怀疑域名服务器被劫持。

 在安卓平台上,通过系统方法获得的解析结果信息非常有限,上面的一些索引将无法获得。因此,在实践中,我们将自己构造DNS查询消息,并向运营商的多个DNS服务器发起查询。

 根据以上指标的综合评价,当本地域名表现不佳时,我们将在策略上对HTTP域名进行升级,试图为用户获得更好的域名解析结果。

 在域名解析过程中,还有一个我们更关心的指标,即域名解析的时间消耗:

 1)当1)本地域名过期时,它将启动一个递归查询,这是不可控制的,在某些情况下甚至可以达到几秒钟的级别;

 2)HTTP域名系统相对较好,但通常需要200毫秒左右。

 这一次可以进一步优化吗?

 我们的软件开发工具包在本地建立了自己的记录缓冲池,每次通过本地域名解析或HTTP域名解析获得的记录都存储在缓冲池中。

 当然,这是一种常见的做法,系统底部的netdb库也是以这种方式实现的。

 不同之处在于我们做了一个小小的改变:对于过期的记录,我们采用了惰性更新策略。当发现过期的缓存记录时,过期的记录将首先返回给用户,然后将异步启动DNS查询来更新缓存记录。

 这一小小的改变可以确保我们在第二次解析时能够命中本地缓存,这大大减少了解析DNS的耗时,但也带来了一些风险。

 因此,在实践中,我们还将增加异步和常规的DNS记录缓存池扫描功能,及时发现和更新缓存中的过期记录,减少应用命中过期记录的发生。

 5.探索米托APP的非侵入式SDK访问方法

 在域名系统优化的实践中,我们遇到的最大问题不是策略层面的设计问题,而是我们的域名系统软件开发工具包应用于实际应用产品业务时的姿态问题。

 5.1IP直接连接方案和各种凹坑

 在行业内,实际业务中的HTTP DNS接入方式大多采用IP直连的形式,即原本直接请求http://www.meitu.com。现在,我们首先调用SDK进行域名解析,得到IP地址如1.1.1.1,然后用http://1.1.1.1/.替换域名

 在此操作之后,由于网址中的主机已经是一个IP地址,网络请求库将跳过域名解析链接,直接向1.1.1.1服务器发送一个HTTP请求。

 在实践中,我们已经为IP直连方案踩了很多洞。

 首先,对于HTTP请求,在采用IP直接连接方案后,我们仍然需要在报头中手动配置主机:

 网址=新网址(" http://1 . 1 . 1 . 1/";

 HttpRelconnection连接=(HttpRelconnection)HTMlURl . Openconnection();

 connection . SetRequestProperty(" Host ","

 HTTP协议相对简单,只需要处理主机,HTTPS呢?

 发起HTTPS请求需要首先进行SSL/TLS握手,其过程如下:

 1)客户端发送客户端问候,携带随机数、支持的加密算法和其他信息;

 2)服务器收到请求后,选择适当的加密算法,并将其与公钥证书、随机数和其他信息一起返回给客户端;

 3)客户端检查服务器端证书的有效性,计算并生成随机数,用证书的公钥加密后发送给服务器端;

 4)服务器通过私钥获取随机数信息,根据之前的交互信息计算获取协商密钥,并通知客户端;

 5)客户端验证服务器发送的数据和密钥,并通过双方握手完成加密通信。

 在我们采用了知识产权直接连接的形式后,HTTPS的第三步就会出现上述问题。

 客户端验证服务器颁发的证书。该操作包括两个步骤:

 1)客户端用本地保存的根证书解锁证书链,并确认服务器的证书是由可信机构颁发的;

 2)客户端需要检查证书的域域和扩展域是否包含此请求的主机。

 证书的验证要求两个步骤都通过验证,然后才能执行后续过程,否则SSL/TLS握手将失败并在此结束。

 因为有了IP直接连接,我们给网络请求库的URL的主机部分已经被IP地址替换了。

 因此,在证书验证的第二步,“此请求的主机”默认为一个IP地址,这将导致域检查不匹配和SSL/TLS握手失败。

 那么如何解决这个问题呢?

 SSL/TLS握手中域名验证问题的解决方案在于重新配置主机名验证器,并让请求库使用实际的域名进行域名验证。

 代码示例如下:

 01020304050607080910111213141516171819最终网址htmlUrl =新网址(“https://1 . 1 . 1 . 1/”;HttpsurlCOnnection =(HttpsurlCOnnection)HTMlURl . OpenCOnnection();connection . SetRequestProperty(" Host ","connection.setHostnameVerifier(新的HostNameVerifier(){ @重写公共布尔验证(字符串主机名,会话会话){返回HttpsurlConnection . GetDefaultHostNameVerifier()。验证(" www.meipai.com ",会话);} });

 我们已经解决了另一个问题,那么HTTPS的问题在IP直接连接下解决了吗?

 不,HTTPS和SNI的场景需要特殊处理。

 SNI(服务器名称指示)是为了解决一个服务器使用多个域名和证书的SSL/TLS扩展。

 其基本工作原理如下:

 1)服务器配置有多个域名和相应的证书。当客户端与服务器建立SSL链接时,它首先发送它想要访问的站点的域名;

 2)服务器根据该域名返回适当的证书。

 与上述域验证类似,网络请求库发送到服务器的“待访问站点的域名”默认为我们替换的IP地址。

 当服务器收到这样一个以IP地址形式存在的域名时,它会显得很愚蠢,找不到相应的证书,最后它不得不重新颁发一个默认的域名证书。

 接下来会发生的情况是,当客户端检查证书的域时,它会失败,因为服务器颁发的证书与域名不对应。

 最后,SSL/TLS握手失败。

 在SNI场景中,我们有办法解决上述问题吗?

 可以解决的是,SSLSocketFactory需要由客户端定制,但是有相对较多的修改代码,所以我不会在这里列出它们。

 如果我们的SDK要连接到应用的实际业务,我们将处理HTTPS SNI场景,我相信许多学生已经崩溃,连接的工作量实际上并不低。

 在许多情况下可能会有妥协,这种SDK只在Okhttp场景中使用,因为Okhttp本身支持域名系统替换,没有上述问题。

 在米托的实践中,我们不仅希望在Okhttp的要求下进行域名系统的优化,也希望相应的优化能够应用在应用H5页面加载和播放器播放等场景中。

 在这种需求下,IP直连接入方案带来的接入工作量实际上并不低,甚至有些车轮需要更换。

 在最初的实践中,我们确实尝试实现了到每个模块的IP直接连接。然而,即使我们克服了转换的工作量问题,在实际操作中仍然会有许多漏洞。

 5.2米托最终采用的非侵入式域名系统软件开发工具包集成方案

 那么,有没有更合适的技术解决方案可以减少我们的DNS SDK的访问工作量,并考虑各种使用场景,如HTTPS和RTMP协议?

 基于这一目标,我们试图探索一种在实践中有利于业务集成的非侵入式域名系统软件开发工具包集成方案。让我们用安卓平台来解释一下。

 我们知道,在Java级别解析DNS的基本方法是调用以下方法:

 inetaddress . GetalByName(" www . mei pai . com ");

 网络请求库,如在安卓平台上常用的Okhttp和HttpUrlConnection,依赖于这种形式的域名解析。

 我们深入分析了InetAddress的运行过程,大致如下:

 米托应用的移动域名系统优化实践:HTTPS请求时间减少了近一半_ 5.jpeg。

 在上面的过程中,我们可以知道InetAddress将转到AddressCache来尝试获取缓存的记录,其中Addresscache是一个静态映射结构变量。

 因此,这里我们要用它做一些小事情:

 1)模拟系统的地址缓存来构造我们自己的地址缓存结构,但是它的获取方法被从我们的SDK获取解析记录所代替;

 2)用我们以反射形式修改的地址缓存替换系统的地址缓存变量。

 在此操作之后,对Java层网络请求(如HttpsUrlConnection)的DNS解析将是这样一个过程:

 米托应用的移动域名系统优化实践:HTTPS请求时间减少了近一半_ 6.jpeg。

 通过这种形式,我们可以很好地解决域名系统软件开发套件在Java层的访问问题。对于业务方来说,他们不需要做任何网址替换操作,相应的问题在HTTPS场景中不再存在。

 Java层的访问解决了,但是本地层呢?

 我们知道,在安卓平台上,诸如网络视图、播放器等模块。,都在本地层连接到网络,不会在Java层调用InetAddress方法。

 在C/C++层,我们知道getaddrinfo或gethostbyname2函数将用于DNS解析。

 此外,我们还知道,在像安卓这样的Linux系统下,文件等可共享对象。所以将以ELF文件格式。

 因此,从这些已知信息中,我们可以得到以下情况:系统libc.so中的getaddrinfo函数直接用于我们的应用程序中的一个. so中,因此根据ELF文件规范,在一个. so的rel.plt表中会有以下关系定义:getaddrinfo = = > 0x ffffffff。

 中的映射关系。rel.plt表指示外部符号getaddrinfo在当前存储器空间中的绝对地址,用于so的操作..

 在正常情况下,从a.so到getaddrinfo的功能流程如下:

 米托应用的移动域名系统优化实践:HTTPS请求时间减少了近一半_ 7.png。

 所以在这里,我们可以手动修改映射表,并用my_getaddrinfo地址替换getaddrinfo的内存地址吗?

 这样,在实际操作中,a.so将被转移到我们的my_getaddrinfo?

 事实上,这确实是可行的。我们试图修改。在软件开发工具包启动后,将软件开发工具包的表关联起来,以便接管软件开发工具包的域名系统..

 修改后的a.so操作流程如下:

 米托应用的移动域名系统优化实践:HTTPS请求时间减少了近一半_ 8.jpeg。

 通过以上方式,我们可以很好地在Java层和本地层接管应用的DNS过程,并且实现使用我们的DNS SDK的优化效果,而无需业务方进行任何额外的更改。

 6.SDK上线后的性能

 在实践中,我们取得了良好的效果。由于域名系统软件开发工具包在达到本地缓存率方面的策略优化,我们的移动产品的网络请求中域名系统解析的时间消耗减少了。

 从实际监控数据来看,整个网络请求的时间消耗也可以减少约100毫秒:

 米托应用的移动域名系统优化实践:HTTPS请求时间减少了近一半_ 9.png。

 通过引入HTTP DNS和本地DNS的优化升级策略,我们的网络请求成功率有所提高,未知主机的特定错误率呈下降趋势。

 由于SDK本身已经进行了灵活的策略配置,我们还通过在线监控和配置使每种产品实现了收益和成本之间的最佳平衡。

 附录:更多关于网络传播的精英文章

容联云  来源: - 即时通讯开发者社区!