安卓性能专项之流量测试篇

从一个Bug说起

之前的项目曾经遇到这样一个问题:

在弱网环境下,几乎每次打开排行榜,都会出现小菊花(加载中),但是在wifi环境下则不会,初步猜测是数据包太大,导致加载速度慢。

使用工具一查,进入排行榜,服务端返回的数据包居然达到了20KB,而我们的竞品,只有2.36KB。

流量测试是什么

流量测试是安卓APP性能测试的其中一个专项,测试APP在联网环境下,网络流量的消耗情况。

流量测试怎么做

使用过以下几种方式:

  • 通过Adb获取流量数据,TesterHome上的一篇文章有详细的讲述,就不再重复了,点击访问

  • 使用tcpdump抓包,使用wireshark分析。

  • 使用性能测试工具GT,Wetest,Emmagee,记录流量数据后,导出查看。

  • 在游戏代码中打印,汇总流量数据。

最简单有效的方式

使用GT这类成熟的性能测试工具,可以直接生成csv文件导出,或者在云端通过图表形式展示。

1
2
3
4
5
6
7
8
9
10
11
transmitted received
min 19 108
max 22 137
avg 21 132
11:41:15.2 19 108
11:41:16.4 20 111
11:41:17.5 21 136
11:41:18.7 22 136
11:41:19.8 22 137
11:41:21.0 22 137

不足之处,只是单纯记录每一秒的流量消耗,无法记录是什么操作产生的流量消耗。另外,如果同一秒中产生了多个请求,消耗的记录会积累到一起。

tcpdump+wireshark可以精确到每一个请求产生的流量消耗,同样也无法直观知道具体是哪个操作。

最精确直观的方式

怎么样才能直观地查看每一个请求所属的操作呢?答案是自制一个流量统计工具。

工具原理:

在客户端代码内,每次请求发送与接收的时候,嵌入统计流量的代码,并汇总到一起,完成测试后,输出到文本上。

保存流量数据的工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TrafficCount {
private static Queue<string> trafficInfo = new Queue<string>();
public static void Add(string s) {
trafficInfo.Enqueue(s);
}
public static void WriteToFile(string filePath) {
StreamWriter sw = new StreamWriter(filePath);
foreach(var i in trafficInfo) {
sw.WriteLine(i);
}
sw.Close();
Debug.LogWarning("成功保存");
}

在客户端发送请求和接收响应的地方加入流量统计(已发送请求为例,截取了部分代码,这里采用了硬编码的方式,其实不太合理)

1
2
3
4
5
6
7
8
9
10
11
12
SocketError error;
var sended = mSocket.Send(output, SocketFlags.None, out error);
if (error == SocketError.Success) {
obj.OK();
//统计代码
this.Debug("成功发送 {0} 字节数据", sended);
TrafficCount.Add("成功发送"+ sended + "字节数据");
//统计代码
} else {
obj.Error();
this.Error("发送数据失败: {0}", error.ToString());
}

在主场景上,挂一个MonoBehaviour脚本,来调用开始统计和保存文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void OnGUI() {
if (GUI.Button(new Rect(0, (Screen.height/2), 50, 30), "流量测试")) {
//监听发送请求和接收返回,获取操作的协议号
EventHelper.Ins.Get<SystemEventGroup>().onRequest.AddHandler((ss, req) => {
Debug.Log(req.Protocol);
TrafficCount.Add(req.Protocol.ToString());
});
EventHelper.Ins.Get<SystemEventGroup>().onResponse.AddHandler((ss, req) => {
Debug.Log(req.Protocol+"成功返回");
TrafficCount.Add(req.Protocol + "成功返回");
});
}
if (GUI.Button(new Rect(0, (Screen.height/2)+50, 50, 30), "保存")) {
TrafficCount.WriteToFile(@"C:\VSTest\result.txt");
}
}

最终输出的文本是:

1
2
3
4
5
6
7
8
110101
成功发送77字节数据
接收到了55字节数据
110101成功返回
107501
成功发送84字节数据
接收到了28字节数据
107501成功返回

怎么优化

  • 去除响应包的冗余内容,如排行榜只需要名称,所在工会,等级等数据,并不需要玩家阵型数据。
  • 有些系统,无需每次点击都请求最新数据,如排行榜,进入后第一次点击里边的各个榜单会请求数据,在退出排行榜之前,再次切换榜单,会读取旧数据,不再发送新请求。

结论

时间段内流量的总消耗测试,建议使用GT类的工具。

具体协议的流量消耗测试,使用自制工具分析。