网络优化

网络优化

优化维度

  • 流量维度
    • 一段时间流量消耗的精准度,网络类型、前台还是后台
    • 监控线上用户流量消耗均值、异常率(流量消耗过度、请求次数过多、下载的文件过大)
    • 理想情况下可以完整链路监控(RequestResponse),主动上报
  • 质量维度
    • 用户体验:请求速度、成功率
    • 监控相关:请求时长、业务成功率、失败率、Top失败接口

工具选择

  • Network Profiler
  • 抓包工具:断点功能、Map Local 、弱网环境模拟
    • Charles:Java 开发跨平台,mac 使用比较多
    • Fiddler:Windows 上面使用比较多
    • Wireshark
    • TcpDump
  • Stetho

精准获取流量消耗

如何判断流量偏高
  • 绝对值不看高低
  • 与竞品对比,相同功能的情况下对比流量消耗
  • 后台监控到流量超过正常指标
流量测试方案
  • 线下流量测试方案

    • 手机设置只有目标应用可以联网
    • 通过抓包工具限制只允许本APP联网。【注:不能以域名为限定基准,因为有的三方SDK、网页等你并不清楚它们的域名,所有会把本应放行的域名给拦住了】
    • 上述两种方式可以解决大多数问题,但是线上场景可能抓不全,如有的H5 zip包并不一定是随app版本一起发布
  • 线上流量消耗方案

    • 通过 TrafficStats (API8)获取流量:

      【缺点】无法获取某个时间段的流量消耗

      1
      2
      3
      4
      5
      6
      TrafficStats.getUidRxBytes()	// 指定Uid所有网络接收的流量
      TrafficStats.getUidTxBytes() // 指定Uid所有网络发送的流量
      TrafficStats.getMobileRxBytes() // 获取手机移动网络接收的流量
      TrafficStats.getMobileTxBytes() // 获取手机移动网络发送的流量
      TrafficStats.getTotalRxBytes() // 获取手机所有网络接收的流量
      TrafficStats.getTotalTxBytes() // 获取手机所有网络发送的流量
    • 通过 NetworkStatsManager (API23)获取流量统计【推荐】

      可以获取指定时间间隔内的流量信息和不同网络类型下的消耗

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      public static long getNetData(Context context, long startTime, long endTime) {
      long netDataRx = 0;
      long netDataTx = 0;
      TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
      NetworkStatsManager networkStatsManager = (NetworkStatsManager) context.getSystemService(Context.NETWORK_STATS_SERVICE);
      NetworkStats networkStats = null;
      try {
      networkStats = networkStatsManager.querySummary(ConnectivityManager.TYPE_MOBILE, telephonyManager.getSubscriberId(), startTime, endTime);
      } catch (RemoteException e) {
      e.printStackTrace();
      }
      if (networkStats == null) return 0;
      NetworkStats.Bucket bucket = new NetworkStats.Bucket();
      int uid = getUidByPackageName(context);
      while (networkStats.hasNextBucket()) {
      networkStats.getNextBucket(bucket);
      if (uid == bucket.getUid()) {
      netDataRx += bucket.getRxBytes();
      netDataTx += bucket.getTxBytes();
      }
      }
      return netDataRx + netDataTx;
      }

      public static int getUidByPackageName(Context context) {
      try {
      PackageManager pm = context.getPackageManager();
      ApplicationInfo ai = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
      return ai.uid;
      } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
      }
      return -1;
      }
  • 前后台流量获取方案

    后台定时任务 -> 获取间隔内流量消耗 -> 区分此时的前后台状态保存数据 -> 合适的时机将数据上报

    【注:该方案有一定的误差,但是该误差处于可接受范围】

网络请求流量优化

流量消耗点
  • 数据:API、资源包(升级包、H5、RN、flutter)、配置信息
  • 图片:上传、下载
  • 监控:APM相关、单点问题
优化点
  • 服务端返回数据加上过期时间,客户端网络框架做好缓存逻辑,节约流量且能大幅提高数据访问速度
  • 数据增量更新,给数据加上版本的概念,只传输有变化的数据,例如配置信息、省市区县等并不会经常变化的数据
  • 请求响应数据压缩,对Post请求Body使用 Gzip 压缩,如需最求更高压缩率可以使用 brotli
  • 请求头压缩,对一些共性请求头可以在服务器中做好MD5的缓存,客户端只需传递该MD5即可,无需每个请求都携带完整的请求头
  • 图片视频压缩,在无需保存源文件的场景下可以在上传之前本地先行压缩数据
  • 优化网络发送频率和时机,相应打点信息性能日志等需要合并网络请求减少请求次数,缓存一定量值或 wifi 下才上报
  • 条件允许的情况下优先显示缩略图和更优编码的格式图片,需要服务端提供多分辨率图片和格式转码的支持

网络请求质量优化

质量指标
  • 网络请求成功率
  • 网络响应速度
请求过程
  1. 请求到达运营商 Dns 服务器并解析成对应的 IP 地址
  2. 创建连接,根据 IP 地址找到相应的服务器,发起一个请求
  3. 服务器找到对应的资源原路返回访问的用户
【优化点】DNS 相关
  • 问题:DNS被劫持、DNS解析慢
  • 方案:使用 HttpDNS, 绕过运营上域名解析的过程,不使用传统的DNS协议向53端口发送请求,而是使用HTTP协议向DNS服务器的80端口发送请求
  • 优势:可以绕过DNS劫持的风险、降低平均访问时长、提高连接成功率
【优化点】协议版本升级
  • 1.0:版本TCP连接不复用
  • 1.1:引入持久连接,但数据通信还是按顺序进行
  • 2.0:多工,客户端、服务器双向实时通信
网络请求质量监控

之所以客户端也需要做网络监控,是因为有的网络请求并没有到服务器就失败了,服务器没法统计

  • 在相应的网络请求库中增加接口请求耗时、成功率、错误码监听统计
  • 在图片请求库中增加图片加载的每一步耗时统计
网络容灾机制
  • 备用服务器分流
  • 多次失败后一定时间内不再进行请求,避免雪崩效应【注意:时间间隔各个用户应该是随机的,避免间隔一段时间后还是出现大批量的请求】
其它
  • CND加速、提高带宽、动静态资源分离(更新后清理缓存)
  • Okhttp 默认单个域名同时请求数量位5个,这是为了防止某个域名请求过多,其它域名的请求没法执行,如果做了域名收敛,只有一个域名,那么可以适当增加单个域名最大同时请求数量