如何应对 Android 面试官 -> 网络如何优化?

前言


本章节主要讲解下 网络如何进行优化;

网络请求大致的实际流程:

  • 根据域名进行DNS解析(域名转换为IP 就是DNS解析,udp协议)
  • IP
  • Socket 连接(TCP/IP的三次握手)
  • 根据 Http 报文格式 将数据进行封装,然后根据与服务器建立的 socket 获取到 OutputStream 把我们的 Http 报文发给服务端,这样就完成了 Http 的请求;

在这个过程中有哪些可以优化的流程呢,大致可以分为以下几个方向

  • DNS 优化
  • 连接优化
  • 数据优化
  • 图片优化
  • 缓存优化
  • 安全优化
  • 其他优化

DNS 优化


要了解 DNS 如何优化,我们需要先来了解下传统 DNS 的解析流程;

传统 DNS 解析流程

DNS(Domain Name System),它的作用是根据域名查出 IP 地址,它是 HTTP 协议的前提,只有将域名正确的解析成 IP 地址后,后面的 HTTP 流程才能进行;

DNS 完整的解析流程很长,会先从本地系统缓存(运营商localDNS)取,若没有就到最近的 DNS 服务器取,若没有再到主域名服务器取,每一层都有缓存,但为了域名解析的实时性,每一层缓存都有过期时间。

传统的 DNS 解析都是使用的 UDP 协议;传统的 DNS 解析有以下几个缺点:

  1. 缓存时间设置过长,因为是优先请求运营商本地 DNS,而运营商的 localDNS 有缓存,导致 DNS 更新不及时,如果缓存设置过短,那么就会像目标服务器进行请求,大量 DNS 解析请求影响请求速度;运营商的 LocalDNS 服务。这块耗时在 3G 网络下可能是 200~300ms,4G 网络也需要 100ms;
  2. 不稳定性,域名劫持,例如 访问 www.baidu.com 结果返回的是一个充值页面;UDP 协议,无状态,容易域名劫持(难复现、难定位、难解决),每天至少几百万个域名被劫持,一年至少十次大规模事件;
  3. 不准确性,DNS解析过程不受控制,无法保证解析到最快的IP,比如:请求者在湖南,结果返回了新疆的ip 这样就会影响请求速度,而如果返回就近的ip则会提升请求速度;LocalDNS 调度经常出现不准确,比如北京的用户调度到广东 IP,移动的运营商调度到电信的 IP,跨运营商调度会导致访问慢,甚至访问不了;
  4. 一次请求只能解析一个域名;
  5. 不及时性;运营商可能会修改 DNS 的 TTL,导致 DNS 修改生效延迟。不同运营商的服务实现不一致,我们也很难保证 DNS 解析的耗时;

那么如何进行优化呢? 使用 HttpDNS

HttpDNS

原理:自己做域名解析的工作(使用 http 协议来进行 DNS 的解析工作),通过 Http 请求后台去拿到域名对应的 ip 地址;

优点:

  • 由于 HttpDns 是通过 IP 直接请求 http 获取服务器 A 记录的地址,不存在向本地运营商请求 domain 解析的过程,从根本上避免了劫持问题;
  • DNS 解析由自己控制,可以确保根据用户所在地返回就近的 IP 地址,或根据客户端测速结果使用最快的 IP;
  • 一次请求可以解析多个域名;

这里以阿里的 HttpDNS 为例子,讲一下如何接入;

阿里 HttpDNS

文档链接:Android端HTTPDNS+OkHttp接入指南

接入指南:help.aliyun.com/document_de...

百度 HttpNDS

文档链接:百度App网络深度优化系列《一》DNS优化

只连 IP

设置 header 的时候 设置 host,将 host 直接改成 IP;

连接优化


本质就是:Keep-alive(连接复用)

Keep-alive 原理是:请求完成后不立即释放连接,而是放入连接池中,若这时有另一个请求要发出,请求的域名和端口是一样的,就直接拿出连接池中的连接进行发送和接收数据,减少了建立连接的耗时;

Http 协议中的一个请求头,HTTP 1.1 默认开启,一定程度上缓解了每次请求都要进行 TCP 三次握手建立连接的耗时;

如何开启:客户端在请求头中 添加 Connection Keep-Alive;

开启之后,说明 客户端希望与服务端保持一个长久的连接,HTTP 底层是 TCP/IP 而 TCP/IP 可以用 socket 建立连接,所以 HTTP 其实就用客户端和服务端用 socket 建立的一个连接,然后用 socket 按照 Http 协议的格式来收发数据;

HTTP 1.1之后新增的 keep-alive 不是客户端想保持长连接就能保持的,如果服务端回复的是 keep-alive 那么可以保持,如果 服务端回复的是 close 那么就会断开这个长连接;

连接复用的优点:

本质上是这个 socket 可以被用来复用,这样就不用每次都经历握手的操作,加快通信的效率;

连接复用的缺点:

  • Http 1.1一次只能发送一个请求

    1)串行发送,可以一直复用一个连接,但速度很慢,每个请求都要等待上个请求结束之后才能发送;

    2)并行发送,那么只能每个请求都要进行 TCP 的三次握手建立连接;

连接复用的缺点如何改良:多路复用;

Http2 提出了『多路复用』去解决,复用的连接支持同时处理多条请求,所有的请求都可以并发到这个连接上进行;

多路复用原理图如下:

原理就是:把传输的数据封装成一个一个的 stream,每个 stream 都有标识,stream 的发送和接收可以是乱序的,不依赖顺序,也就不会有阻塞问题,接收端可以根据 stream 的标识来区分属于哪个请求,再进行数据拼接,得到最终的数据;

简单来说就是:同时发起两个请求,这两个请求复用同一个 socket,这就叫多路复用规则;

Http 2 的缺点:

  • 一个是同一条 H2 连接只支持同一个域名;
  • 一个是后端支持 HTTP/2.0 需要额外的改造;

如何解决:

我们只需要在统一接入层做改造,接入层将数据转换到 HTTP/1.1 再转发到对应域名的服务器;

数据优化


来聊数据优化的时候,我们需要看下数据对网络请求速度的影响的因素有哪些?一个是:压缩率;一个是:解压序列化反序列化的速度;

优化方向:

  1. 请求头 header;
  2. 请求 URL;
  3. 请求体 body;

请求头 header

  • 对于 header 来说,如果使用 HTTP/2.0 连接本身的头部压缩技术;

请求 URL

  • 对于请求 URL 来说,一般会带很多的公共参数,这些参数大部分都是不变的。这样不变的参数客户端只需要上传一次即可,其他请求我们可以在接入层中进行参数扩展;

请求体 body

  • 数据序列化

    • protobuf,优点:二进制,数据更加的紧凑,都压缩后 也会比json小,序列化速度也比json快,缺点需要后台支持
    • json
  • 数据压缩

    • gzip数据压缩
      • Accept-Encoding : gzip;客户端支持服务端将数据进行 gzip 压缩之后传递给客户端
    • Google 的Brotli
    • Facebook 的Z-standard

protobuf 使用

  • 引入 lite 版本的 protobuf 组件

  • 创建 proto 文件

  • project下的 build.gradle 引入 protobuf 插件
  • app.build 下 引入插件并进行相关配置
  • build之后 就会生成对应的java文件

gzip 使用

开启 gzip 压缩

服务器响应 gzip 压缩

客户端发送 gzip 压缩之后的数据

图片优化


优化手段

不同网络类型,下发不同图片

每一次请求的请求头 都加上网络类型和网络信号,来获取不同网络状态下的图片;

使用 WebP 替换 PNG 图片

缓存优化


优化手段

开启 Http 缓存

设置『缓存路径』和『缓存空间』

模拟无网、弱网环境

模拟断网

模拟超时

模拟限速

安全优化


优化手段:HTTPS

HTTPS

连接复用率

通过多个域名共用同一个 HTTP/2 连接、长连接等方式提升连接复用率

减少握手次数

TLS 1.3 可以实现 0-RTT 协商,事实上在 TLS 1.3 release 之前,微信的 mmtls、Facebook 的 fizz、阿里的 SlightSSL 都已在企业内部大规模部署;

性能提升

使用 ecc 证书代替 RSA,服务端签名的性能可以提升 4~10 倍,但是客户端校验性能降低了约 20 倍,从 10 微秒级降低到 100 微秒级。另外一方面可以通过 Session Ticket 会话复用,节省一个 RTT 耗时;

好了,网络优化就写到这里吧~

欢迎三连


来都来了,点个关注,点个赞吧,你的支持是我最大的动力~

相关推荐
快乐的木子李9 分钟前
Java核心技术面试题
java·开发语言
chaser&upper1 小时前
Spring 服务调用接口时,提示You should be redirected automatically to target URL:
java
一切皆有迹可循3 小时前
IntelliJ IDEA中Spring Boot项目整合MyBatis:从零实现高效数据持久化
java·spring boot·intellij-idea·mybatis
雾月555 小时前
LeetCode 941 有效的山脉数组
java·开发语言·数据结构·算法·leetcode·职场和发展
QING6186 小时前
【LeakCanary】的实现原理与调优技巧
android·性能优化·app
QING6186 小时前
Android LruCache 与 DiskLruCache 深度解析
android·kotlin·app
小诸葛的博客7 小时前
Apache BookKeeper Ledger 的底层存储机制解析
java
半旧5187 小时前
重构谷粒商城11:node快速入门
java·前端·重构
嘤国大力士7 小时前
C++11&QT复习 (十六)
java·开发语言·c++
菜鸟起航ing7 小时前
【Java面试系列】Spring Boot中自动配置原理与自定义Starter开发实践详解 - 3-5年Java开发必备知识
java·spring boot·面试·自动配置·自定义starter