网络优化
网络请求 APM
埋点采集网络请求的各个阶段的数据:tsl 连接,TCP 握手,连接池复用率等
网络优化思路
常规
OkHttpClient 单例化
整个项目用一个 OkHttpClient 实例
请求/响应 body 压缩
- 开启 gzip 压缩
HttpUrlConnection
,在请求头增加Accept-Encoding:gzip
,服务端返回头content-encodeing:gzip
,然后客户端处理响应体时,进行 gzip 解压缩- OkHttp 自动设置了 gzip 压缩?
- 请求 body 用 gzip 对内容进行压缩;mashi 后续用到的是
brotli
- 响应 body 也要 gzip 进行压缩
域名合并方案
随着开发规模逐渐扩大,各业务团队出于独立性和稳定性的考虑,纷纷申请了自己的三级域名。App 中的 API 域名越来越多。
search.api.dianping.com
ad.api.dianping.com
tuangou.api.dianping.com
waimai.api.dianping.com
movie.api.dianping.com
App 中域名多了之后,将面临下面几个问题:
- HTTP 请求需要跟不同服务器建立连接。增加了网络的并发连接数量
- 每条域名都需要经过 DNS 服务来解析服务器 IP
阻力:
如果想将所有的三级域名都合并为一个域名,又会面临巨大的项目推进难题。因为不同业务团队当初正是出于独立性和稳定性的考虑才把域名进行拆分,现在再想把域名合并起来,势必会遭遇巨大的阻力。
方案:
保持客户端业务层代码编写的网络请求与后端业务服务器收到的请求保持一致,请求发出前,在客户端网络层对域名收编,请求送入后端,在 SLB(Server Load Balancing) 中对域名进行还原。
网络请求发出前,在客户端的网络底层将 URL 中的域名做简单的替换,我们称之为 “域名收编“。
例如:URL “http://ad.api.dianping.com/command?param1=123” 在网络底层被修改为 “http://api.dianping.com/ad/command?param1=123” 。
- 所有 URL 的域名都被合并为 “api.dianping.com”
- 子级域名信息被隐藏在了域名后的 path 中。
- 被改造的请求被送到网络后端,在 SLB 中,拥有与客户端网络层相反的一套域名反收编逻辑,称为 “ 域名还原 “。
优点:
- 域名得到了收编,减少了 DNS 调用次数,降低了 DNS 劫持风险。
- 针对同一域名,可以利用 Keep-Alive 来复用 Http 的连接。
- 客户端业务层不需要修改代码,后端业务服务也不需要进行任何修改
HTTPS IP 直连
HTTPS IP 直连优点
- 摒弃了系统 DNS,减少外界干扰,摆脱 DNS 劫持困扰。
- 自建 DNS 更新时机可以控制。
- IP 列表更换方便。
- 就近接入甚至就快接入,减少耗时
- 当终端有多个 IP 接入选择时,有一定容灾能力
HTTPS IP 直接问题
证书 Host 校验问题
Client 在 TLS 握手过程的证书校验阶段会校验当前请求 URL 的 HOST 是否在服务端证书的可选域名列表里,由于请求的 HOST 被替换成了 IP,导致底层在进行证书的 HOST 校验时失效,最终请求失败。
解决:系统提供了接口,允许 Client 设置证书 HOST 校验实现,直接将底层默认实现中取 Client 传入 URL 的 HOST 替换成 IP 直连前的域名即可。
SNI 问题
一个服务器 IP 部署了多个域名的证书
连接复用问题
连接复用失效问题
解决: 自定义 HostnameVerifier
兼容性问题
Session 复用问题
SSL 握手过程中,密钥协商是其中最耗资源和时间的过程,Session 复用能节省协商的消耗。Session 复用同样需要 CS 双方支持。
https 转 http
网络层最有效的优化,是将这个接口的 https 切换成 http,做内部私有的安全校验和加解密。(微信好像都是这么玩的)
HttpDNS
DNS 协议
IP 地址不方便记忆且不能很好的显示公司名称和性质的缺点,设计出了域名;通过 DNS(域名解析协议) 来将域名和 IP 地址互相映射,不用记住 IP 地址就可以访问网站
背景
我们的服务经常会遭遇到运营商的 DNS 劫持,导致 web 页面出现弹窗、小广告、服务不稳定、不可用等。
DNS 协议可以使用 UDP 或 TCP 进行传输,使用的端口号为 53,但大多数情况下 DNS 都使用 UDP 进行传输。
域名劫持 (DNS 劫持)
域名劫持又称 DNS 劫持,DNS 劫持即通过某种技术手段,篡改正确域名和 IP 地址的映射关系,使得域名映射到了错误的 IP 地址,因此可以认为 DNS 劫持是一种 DNS 重定向攻击。
DNS 劫持通常可被用作域名欺诈,如在用户访问网页时显示额外的信息来赚取收入等;也可被用作网络钓鱼,如显示用户访问的虚假网站版本并非法窃取用户的个人信息。
常见域名劫持现象:
- 广告劫持:用户正常页面指向到广告页面。
- 恶意劫持:域名指向 IP 被改变,将用户访问流量引到挂马,盗号等对用户有害页面的劫持。
- local DNS 缓存:为了降低跨网流量及用户访问速度进行的一种劫持,导致域名解析结果不能按时更新。
HTTPDNS
什么是 HTTPDNS?
HTTPDNS 是面向移动开发者推出的一款域名解析产品,具有域名防劫持、精准调度的特性。
HTTPDNS 使用 HTTP 与 DNS 服务器交互,代替传统的基于 UDP 的 DNS 协议,域名解析请求直接发送到 HTTPDNS 服务端,从而绕过运营商的 Local DNS。(腾讯云和阿里云都提供了 HttpDNS 服务)
HTTPDNS 特性
- 防止域名劫持
由于 HttpDns 是通过 IP 直接请求 HTTP 获取服务器 A 记录地址,不存在向本地运营商询问 domain 解析过程,所以从根本避免了劫持问题。
- 精准调度
HTTPDNS 能够直接获取到用户的 IP 地址,就近下发服务器的 IP,从而实现精确定位与导流
- 用户连接失败率下降
通过算法降低以往失败率过高的服务器排序,通过时间近期访问过的数据提高服务器排序,通过历史访问成功记录提高服务器排序。
怎么保证请求 HTTPDNS 服务器没有被劫持?
使用 ip 直连到 httpdns 服务器,就可以避免了域名被劫持
IP 直连的问题
HTTPDNS IP 直连的证书校验问题
SNI 问题(一个服务器配置了多个域名)
连接复用
使用 HTTP2/QUIC 协议
升级到 HTTP2 协议
使用 QUIC 协议
Chromium 开源的 cronet,替换掉 okhttp 的传输层
数据格式采用高压缩率的数据序列化
用 MessagePack/protobuf 替代 JSON
MessagePack
结构和 JSON 一样,比 JSON 更小更快,今日头条的多闪在用;热猫和 mashi 的聊天室的消息在用
原理: MessagePack 是一种高效二进制序列化格式。可以在多种语言中进行快速数据交换,比如 JSON 格式等。这种格式小巧快速,多个小整数会压缩成一个字节,通常短字符串压缩后只比原来长度增加 1 个字节。MessagePack 支持超过 50 种编程语言和环境。
protobuf
protobuf,全称:Google Protocol Buffer,是 Google 开源的一种轻便高效的结构化数据存储格式,可以用于结构化数据的串行化,也称作序列化,主要用于数据存储或是 RPC 数据交换,支持多语言,可拓展。
原理
基于 128bits 的数据存储方式 (Base 128 Varints)。
Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。
缓存
- 根据 HTTP 头信息中的
Cache-Control
/Etag
/Last-Since-Modified
及expires域
确定是否缓存请求结果
其他
服务器合理部署;服务器多运营商多地部署
CDN 缓存静态资源
- 只缓存静态资源
- 经常动态变化的不要缓存