Android 网络优化(下)

一、网络优化维度

1、网络优化分析

基础网络的效率就像一辆列车,时延是火车的速度 (启动时间),而带宽就像火车的车厢装载量,整个传输的物理链路就像火车的铁轨。从网络的通信过程来看,共涉及到 三个模块

  • 1)、网络库 SDK 内部的设计与策略:I/O 并发模型,针对网络问题的优化。
  • 2)、服务器性能:并发、带宽能力。
  • 3)、网络相关:用户网络(弱网/强网)、运营商、网络链路等。

而对于网络的优化,我们可以从以下五个维度来进行。
1)、流量优化
精确获取网络流量的消耗量,解决整体均值掩盖单点异常流量的问题。
2)、网络监控
建设全面的网络监控,因为粗粒度的监控不能够帮助我们发现和解决问题。
3)、流量消耗

  • 1、精准获取一段时间的流量消耗、网络类型、前后台。

  • 2、用户流量消耗均值、异常率(消耗多、次数多)。

  • 3、完整链路全监控(Request、Response)、主动上报。
    4)、网络请求质量

  • 1、请求时长、业务成功率、失败率、TOP 失败接口,导致请求失败的原因通常有两种情况:
    1)、弱信号:可以简单看成手机信号只有一两格的时候,这是不仅仅是信令(无线网络通信的都是一个个的信令)发出去困难,还可能导致不断切换网络、基站。App 只能在应用层做重试,因为弱信号一般都是一时的。
    2)、拥塞网络:可以类比为堵车、排队的场景,数据包排队,信令也在排队。这时 App 不断重试,只会使得拥塞网络更为严重。我们只能让自己的非核心业务不要去排队,并让核心业务的数据量更少,协议来回更少。

  • 2、用户体验

  • 3、请求速度、成功率:网络正常时如何更好地利用带宽提升网络请求速度?

  • 4、弱网:网络不稳定是如何最大程度上保证网络的连通性?

  • 5、安全:如何防止被第三方劫持、窃听甚至篡改?
    5)、其它

  • 1、公司成本

  • 2、带宽、服务器数量、CDN

  • 3、耗电

2、网络优化误区

  • 1)、仅仅关注流量消耗,忽视其它维度。
  • 2)、仅仅关注均值、整体、忽视个体。

二、网络优化工具

1、Network Profiler

特点

  • 1)、显示实时网络活动:发送、接收数据及连接数。
  • 2)、需启动高级分析。
  • 3)、仅支持 HttpURLConnection 与 OkHttp
    打开高级分析
    Run => Edit Cofigurations => 界面最右边 Profiling => 打开 Enable advanced profiling (required for API level < 26 only)

使用 Network Profiler 调试 WanAndroid 网络请求
Connection View
选中目标网络请求,可以看到在下方的 Connection View 一栏看到对应的网络数据,如下所示:

Size
Type
Status
Time
Timeline

选中 Connection View 特定的一条数据即可在右边看到该请求对应的网络数据。

Overview
该网络请求的预览信息

普通 Json 数据请求.png

图片加载请求.png

Response
Response Header 与 Body 信息
Request
Request Header 与 Body 信息
CallStack
网络请求的调用堆栈信息, 下图就是 Awesome-WanAndroid 发起一个网络请求所经历的调用堆栈:

2、Charles

特点

  • 1)、断点功能
  • 2)、Map Local
  • 3)、弱网环境模拟

Charles

使用断点功能
1)、右键点击要断点的 URL,选中 BreakPoints 开启断点功能。
2)、点击顶部 Proxy => Breadkpoint Settings。
3)、双击 Breakpoints Settings 面板中的目标
URL,在弹出的 Edit Breakpoint 面板中进行编辑。
4)、这里默认选择断点 Request 与 Response,我们可以选择仅断点 Response 或 Request。点击确认即断点设置完成。
5)、然后,我们就可以点击主面板右侧的 Edit Response 编辑 Response,修改完成后点击最下方的 Execute 即可。

使用 Map Local
1)、自由模拟服务端的返回数据,以提前进行接口测试。
1)、右键点击要使用 Map Local 的 URL,选中Map Local 开启断点功能。
1)、然后,我们在 Edit Mapping 面板中选择 Map To 的 Local path,选择本地设定的 maplocal 本地数据(例如 JsonString)

弱网模拟功能

  • 1)、注意开启前需将 Map Local 关闭。
  • 2)、点击 Proxy => Throttle Setting => 选中 Enable Throttling
  • 3)、这里预设了很多模拟设置,我们只需将 网络包传输的速率 Throttle preset 设置为较低的速率(一般设为 256/512)。

3、Wireshark

geektime-webprotocol

WireShark 主要可以用来对四种流进行跟踪,如下所示:

TCP
UDP
SSL
HTTP

4、TcpDump(网络数据包嗅探器)

tcpdump

5、Stetho

  • 1)、在 build.gradle 中,除了 Stetho 依赖外,还需添加 'com.facebook.stetho:stetho-okhttp3:1.5.0'。
  • 2)、在 Application 的 onCreate 方法中初始化 'Stetho.initializeWithDefaults(this)'。
  • 3)、调用 OkHttp 的 'addNeworkInterceptor' 方法添加 Stetho 用于收集网络信息而提供的网络拦截器。
  • 4)、访问 Chrome 调试页面 'chrome://inspect'

6、其它的性能检测工具

  • strace:跟踪 Socket 相关的系统调用。
  • netstat:记录多种网络栈和接口统计信息。
  • ifconfig:记录接口配置。
  • ip:记录网络接口统计信息。
  • ping:测试网络连通性。
  • traceroute:测试网络路由。
  • /proc/net 命令:查看网络统计信息,Android TrafficState 使用了 /proc/net/xt_qtaguid/stats 和 /proc/net/xt_qtaguid/iface_stat_fmt 文件来统计 App 的流量信息。

三、精准获取流量消耗

1、如何判断 App 流量消耗偏高?

  • 1)、绝对值看不出高低。
  • 2)、对比竞品,相同 Case 对比流浪消耗。
  • 3)、异常监控超过正常指标。

2、测试方案

  • 1)、打开手机设置 => 流量管理 => 仅允许目标 App 联网
  • 2)、可以查找出大多数的问题,但是线上场景线下可能遇不到。

3、线上流量获取方案

1)、TrafficStats

特点

  • API 18 以上。
  • 记录手机重启以来的数据流量。
    API
  • getMobileRxBytes():通过蜂窝流量接收到的信息。
  • getUidRxBytes(int uid):获取指定 uid 的接收流量。
  • getTotalRxBytes():总发送流量。
    缺点
    无法获取某个时间段内的流量消耗。

2)、NetworkStatsManager

API 23 之后。
特点

  • 1)、获取指定时间间隔内的流量信息。
  • 2)、获取不同网络类型下的消耗。
    NetUtils.getStats
    获取指定时间间隔的 蜂窝 + WIFI 流量总信息

4、前后台流量获取方案

问题:线上反馈 App 后天流量消耗大?
只获取一个时间段的流量不够全面。
实现原理
后台定时任务 => 获取时间间隔内流量 => 记录前后台 => 分别计算 => 上报 APM 后台 => 流量治理依据
小结

  • 1)、该方案无法获取应用在前后台切换时的流量,因此有一定的误差,但这个误差是可以接受的。
  • 2)、结合精细化的流量异常报警针对性的解决后台跑流量的问题。

四、网络请求流量优化

1、常见使用网络的场景

1)、数据压缩
POST 请求 Body 使用 GZip 压缩,同时服务端返回 Body 也使用 GZip 压缩。
2)、图片

  • 图片上传前压缩。
  • 图片使用策略细化:让 服务端/CDN 云服务器 优先使用缩略图/WebP格式图片。
    3)、性能日志上报:批量 + 特定场景上报
    APM 相关、单点问题相关。例如埋点数据可以等到某一时机点(例如 开启了 WIFI、数据量过大必须上传一部分时)再上传。
    4)、数据缓存
    服务端返回加上过期时间,避免每次重新获取。 节约流量且大幅提高数据访问速度,更好的用户体验。
    Request 缓存设置
  • 1、Pragma:no-cache:去服务器拉取最新的资源,不使用缓存。
  • 2、If-Modified-Since:datetime:如果资源在客户端提供的时间后发生改变,服务器会返回新的资源,否则使用缓存。
  • 3、If-None-Match:etagvalue:如果资源的标识和服务器的不同,返回新的资源。
    当 Request 的头部是 2 和 3 时,如果服务器的资源没有修改,则服务器会返回 HTTP/304 Not Modified,客户端会使用缓存的 Response。
    Response 缓存设置
    HTTP Response 是否可以缓存是由 Response 的头部控制的,服务器可以通过 Expires 和 Cache-Control 控制 Response 如何在客户端缓存。
    Expires
    Expires 头部会包含一个日期,即该资源缓存的有效期,客户端有新的相同请求时,如果资源缓存没有过期,则使用缓存资源,服务器不会返回任何东西。
    Cache-Control
    Cache-Control 可以标明 Response 如何存储及其如何使用,其选项如下所示:
  • 1)、public:Response 可以存储在任何 Cache 中,包括共享的 Cache。
  • 2)、private:Response 存储在私有 Cache 中,只能被一个用户使用。
  • 3)、no-cache:Response 将来不会被使用。
  • 4)、no-store:Response 将来不会被使用,也不会写到磁盘上。
  • 5)、max-age=#seconds:Response 在设定的时间内可以被重复使用。
  • 6)、must-revalidate:和原始服务器确认 Response 是最新后,可以使用缓存。

OKHttp 无网数据缓存实现
POST 在 OKHttp 中默认不会缓存,因为 POST 一般是用来修改数据的。在 Awesome-WanAndroid 中的 HttpModule—cacheInterceptor 中就已经实现了 OKHttp 的无网数据缓存,代码如下所示:

File cacheFile = new File(Constants.PATH_CACHE);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = chain -> {
    Request request = chain.request();
    if (!CommonUtils.isNetworkConnected()) {
        // 无网时强制使用数据缓存,以提升用户体验。
        request = request.newBuilder()
                .cacheControl(CacheControl.FORCE_CACHE)
                .build();
    }
    Response response = chain.proceed(request);
    if (CommonUtils.isNetworkConnected()) {
        int maxAge = 0;
        // 有网络时, 不缓存, 最大保存时长为0
        response.newBuilder()
                .header("Cache-Control", "public, max-age=" + maxAge)
                .removeHeader("Pragma")
                .build();
    } else {
        // 无网络时,设置超时为4周
        int maxStale = 60 * 60 * 24 * 28;
        response.newBuilder()
                .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                .removeHeader("Pragma")
                .build();
    }
    return response;
};
// 缓存优化
builder.addNetworkInterceptor(cacheInterceptor);
builder.addInterceptor(cacheInterceptor);
builder.cache(cache);

5)、离线包、增量数据更新
加上版本的概念,仅传输有变化的数据。
6)、请求头压缩
如果请求头不变,服务端可以使用映射缓存 请求头 MD5 : 请求头,之后请求头都使用 MD5 即可。
7)、优化发送频率和时机
8)、合并网络请求、减少请求次数。
9)、流量兜底能力
如果发现流量异常,我们可以通过后台服务器终止协议交互,以避免问题恶化。

2、流量统计

我们可以利用 network-connection-class 进行流量统计,它内部使用的是 API 8 的 TrafficStats 类,用于获取整个手机或者某个 UID 从开机算起的网络流量。
1)、四个核心 API

// 从开机开始Mobile网络接收的字节总数,不包括Wifi
getMobileRxBytes()        
// 从开机开始所有网络接收的字节总数,包括Wifi
getTotalRxBytes()     
// 从开机开始Mobile网络发送的字节总数,不包括Wifi
getMobileTxBytes()        
// 从开机开始所有网络发送的字节总数,包括Wifi
getTotalTxBytes()         

2)、对应的Linux 内核 proc 统计接口

// stats接口提供各个uid在各个网络接口(wlan0, ppp0等)的流量信息
/proc/net/xt_qtaguid/stats
// iface_stat_fmt接口提供各个接口的汇总流量信息
proc/net/xt_qtaguid/iface_stat_fmt

3)、工作原理

  • 1)、读取 proc,并将目标 UID 下面所有网络接口的流量相加。
  • 2)、Android 7.0 之后只能通过 TrafficStats 拿到自己应用的流量信息。

参考

深入探索 Android 网络优化(三、网络优化篇)上

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351