如何选择一个技术解决方案

原文地址:http://blog.csdn.net/mba16c35/article/details/75734176

一、问题

这周遇到一个用户反馈,说邮箱的记事本列表一直空白,无法加载任何记事。于是查了日志,发现用户由于记事太多一直网络超时。

			long sTime = SystemClock.elapsedRealtime();
			responseCode = connection.getResponseCode();// 阻塞型
			long elapse = SystemClock.elapsedRealtime() - sTime;

在这里得阻塞34s才能获得数据,而我们的读超时是设置成15s,所以用户一直超时,无法获取数据。

	/**
	 * http
	 * 数据超时 50000ms
	 */
	public static final int READ_TIME_OUT = 15000;

二、如何解决

1.直接原因:超时太短

最简单的做法当然是直接把超时改长,但这真的是本质原因吗?修改超时值是否会引起其他的影响?


2.需要思考些什么

(1)问题发生的本质原因,细化问题产生的过程

要分析问题,首先要拆分问题产生的每个阶段。

看一下http发起请求到收到数据的过程:

//1.打开connection
step = STEP_OPEN;
startTime = SystemClock.elapsedRealtime();
connection = openConnection(request, url);

//2.设置connection的property
setProperty(connection, request, bodyData);
setUserHeads(connection, request);
setUserCookies(connection, request);

...

//3.开始connect
step = STEP_CONNECT;
startTime = SystemClock.elapsedRealtime();
QMLog.log(Log.DEBUG, TAG, "start to establish http connection, url: " + url + ", requestProperties: " + connection.getRequestProperties());
connection.connect();
QMHttpReportManager.connect(SystemClock.elapsedRealtime() - startTime, url, true, null);

//4.上传数据
step = STEP_POST_DATA;
startTime = SystemClock.elapsedRealtime();
...
QMHttpReportManager.post(request.getHttpMethod() == QMHttpMethod.QMHttpMethod_MULTIPART, SystemClock.elapsedRealtime() - startTime, url, true, null);
request.setStatus(QMNetworkRequest.STATUS_SEND_DATA_END);

//5.开始回包
step = STEP_RESPOND;
startTime = SystemClock.elapsedRealtime();

long sTime = SystemClock.elapsedRealtime();
responseCode = connection.getResponseCode();// 阻塞型
long elapse = SystemClock.elapsedRealtime() - sTime;
boolean responseCodeOK = responseCode >= 200 && responseCode < 300;
QMHttpReportManager.response(elapse, url, responseCodeOK, responseCode, null);

//6.接收数据
step = STEP_RECEIVE_DATA;
startTime = SystemClock.elapsedRealtime();
if (responseCodeOK) {
	response = handleSendSuccess(request, connection);
	QMHttpReportManager.read(SystemClock.elapsedRealtime() - startTime, url, true, null);
	step = STEP_HANDLE_DATA;
	error = response.getError();
	request.responseSuccess(response);
	if (subscriber != null) subscriber.onNext(response);
	if (subscriber != null) subscriber.onCompleted();
} else {
	error = handleSendError(request, connection);
	QMHttpReportManager.read(SystemClock.elapsedRealtime() - startTime, url, true, null);
	step = STEP_HANDLE_DATA;
	response = getResponse(request, connection);
	response.setResponseCode(responseCode);
	request.responseError(response, error);
	if (subscriber != null) subscriber.onError(error);
}

//7.完成请求
step = STEP_COMPLETE;

问题出现在第5步,getResponseCode是应用层读取服务器返回的第一个数据。那就是说在数据包完全从app发出,到收到服务器第一个返回数据的过程,需要34s。

而这期间的耗时又由4个部分组成:

a.app的数据到达cgi所耗费的网络耗时。

b.cgi调用后台服务和处理数据的耗时。(cgi相当于后台服务器的代理)

c.cgi写回包的io耗时。

d.cgi的数据到达app端的网络耗时。


分析

由于app的请求很小,于是耗时a是比较小的;

cgi的io读写能力应该是比较强的,于是耗时c也是比较小的;


然后和cgi的同事联调发现,cgi调用后台服务花费了21s,看来瓶颈在b这部分。


既然知道原因,讨论之后我们有3个可选的技术方案:

a.实现分段加载。app给服务器一个时间戳和limit,服务器可以返回时间戳往前最多limit封记事。当返回的数量少于limit时,才是完全加载完。这样每次网络请求的大小可控,超时也就可控。这个方案在性能和用户体验上都是最好的,但是实现的代价比较大。

b.服务器限制只下发前5000封记事,更旧的记事用户的就看不到了。这个方案实现代价很小。

c.app端增加读超时的限制。


(2)衡量方案是否具有可扩展性

c方案是最不具备可扩展性的。当用户10000封记事时,超时需要设成50s,那当有十万封,二十万封时,难道超时数值一直往上调吗?用户等待太久,用户体验也不好。所以c方案不可行。


(3)衡量性价比

实际上记事数量这么多的用户并不多(当然只是一个猜想,可以加上监控证实),所以其实性价比最高的是b方案。当然后面如果有用户投诉的话,还是得使用a方案。


你可能感兴趣的:(如何选择一个技术解决方案)