手机淘宝性能优化

该文章来自于阿里巴巴技术协会(ATA)精选文章。

手机淘宝性能优化

前言

为了满足不同用户的多样性购物需求,过去两年里手淘的业务不断膨胀,已经从单一的购物工具成为了购物内容平台。在手淘业务快速增长的同时,也带来一些副作用,很多操作环节和页面因为承载功能太多,展示的速度变慢,用户等待时间变长。性能优化势在必行。 

我们根据手机淘宝用户的购物操作流程,对主链路进行了划分,分为启动,首页加载,搜索,购物车,下单,支付环节,订单查看等七个环节,每个步骤和模块都做到监控,以量化数据为指导来进行优化。

下面着重就启动,首页,购物车三个业务环节和网络调优,图片下载两个基础能力优化,优化使用的工具来介绍方案。 

一.启动优化

我们通过线下分析工具,线上灰度数据和代码review,发现启动慢主要有3个原因:1)引入了许多提前的初始化;2)在启动阶段主线程,存在耗时的非必要阻塞操作;3)部分主线程的锁操作,导致主线程wait时间较多。

由此制定出优化的方案:

1)启动无网+缓存

执行严格的无网策略,从用户点击图标到首页第一次展示整个过程没有网络交互,所有数据都是缓存或预置数据的方式来获取。这是因为网络IO耗时都比较长,通过将启动阶段的配置信息拉取和首页运营数据的拉取等网络IO后移,减少了时间开销。

 2)Task分级与异步化

我们将启动中的所有task进行梳理和分级,根据级别来调整执行对应task的时机: 

一级:block启动的task,比如基础sdk的初始化,首页页面的创建等。 

二级:可延迟到首页加载成功后再执行的task,比如自动登录,微淘状态拉取,消息数拉取,配置信息拉取,运营数据拉取等操作 。

只有一级task在启动时执行,二级task延迟到启动完成后串行执行,一级task必须没有锁操作,保证主线程不会被阻塞。

 3)懒加载

优化之前在启动过程中有很多业务的初始化操作,现在我们都采用懒加载策略,真正使用时再进行初始化加载,同时懒加载机制可以结合缓存或预置数据的方式来达到更好的效果。

 比如在手淘的五个tab中,在没有优化前,会在启动时将五个tab对应的页面全部创建出来,而这五个页面中,只有首页是可见的,这些页面的创建都会有一定的耗时,而且除了创建以外,可能还会有一些业务逻辑在里面,比如发送一些请求等,那就会对整个启动造成一定的性能损耗。所以在这次优化过程中,我们就使用lazy创建的方式进行优化,启动只创建可见的页面即首页,而其它几个页面,只有在用户点击对应tab时,才进行创建显示,这一个优化减少了近0.5s的耗时。 

 在上述三个主要策略的优化指导下,手淘的启动流程图变为如图1所示的结构(Android情况也类似),从图中可以看出,在主线程中,启动阶段我们只保留了一些必要的初始化,其他一些非必要的操作都被懒加载或者异步化。通过这些策略的调整,我们达到了最开始设定的优化目标。

 手机淘宝性能优化

二.首页优化

作为曝光量最高的页面,快速打开,稳定可用,及时更新是三大目标。

在首页,展示的内容大致分为四类:

  • 二级页面的入口,图标,标题和位置相对固定;
  • 顶部的轮播图,一般为六幅图片,作为不同运营模块或活动的入口;
  • 根据用户身份运算出来的推荐商品,店铺
  • 顶部的消息盒子入口,带未读消息数字图标。

 

对于这四类,采用不同的处理方式:

对于1和2,进行了大量的本地cache化工作,将这些入口文字图标缓存在本地,首先展示上次cache内容,即使遇到无网的情况,首页的整体框架页面,cache过的图片和文字都能绘制出来。

本地cache内容会有一个有效时间戳,在绘制完毕后判断如果cache实际过期了,就会异步网络拉取,下载完毕后做页面刷新。

手机淘宝性能优化 

 

对于3)采用优化页面结构和层次的方法:推荐商品放在页面最下部,当用户主动滚动上滑时做拉取绘制,避免页面一次拉取数据内容过度。

 对于4)采用lazy化,即延迟处理,在首屏其他内容完成基础绘制后,才调用接口拉取未读消息数量。

 同启动步骤,首页这里也使用了任务异步化,目前主流手机都是多核处理器,部分 task 可以充分利用多核优势,放在异步线程里完成。比如首页的数据量是相对比较大的,这些数据的加载,解析,拼装都是非常耗时的操作,通过将这些耗时操作进行异步化,保证主线程的正常调度,只有等数据都准备好了,才在主线程中进行UI的渲染更新,从而保障了主线程的流畅性。

 

三.购物车优化

购物车已经成为用户的“第二收藏夹”,大量用户通过多终端(PC,手机)不断更新购物车的内容。在本地建立缓存保存数据,及时展示给用户是提升打开购物车页面的必然手段。

但购物车中的商品会根据活动,店家,单一商品数量等产生不同的优惠组合,在端A上添加或删除某一个商品,都会产生总价的复杂变化。而这个价格计算规则客户端是无法实时获取到的,由服务端计算完毕后下发。

所以这就导致购物车的价格展示不仅仅是一个简单的“单品价格*商品数量=总价”的公式。客户端在更新时,不断要拉取到商品数量的变化,也要拉取到总价的变化。

以往是采用用户主动刷新时全量更新的方法,现在优化为差量更新,不但流量减少,更有效地提升了拉取和刷新展示的速度。 手机淘宝性能优化

上面从业务环节讲述了优化的方法,这里从基础服务角度来描述优化手段:

四.网络优化

我们都知道主干互联网传输消耗的时间。主要包括三部分时间:DNS查找、TCP/TLS握手、数据传输。如何降低这三部分的耗时是网优的重要手段:

 1)IP直连:

实现方式是HTTP DNS。在启动完成后时发送一次HTTP请求获取一组手机淘宝中使用的域名IP映射表,并缓存在本地。每次发起连接时,直接在网络层使用IP代替域名直连。这种方式除了节省DNS时间,也可以规避掉公网DNS Server被攻击导致的手淘服务瘫痪,这种情况2013年曾经发生过一次,手淘未受任何影响。

 2)建立长连接:通过spdy实现, 减少TCP/TLS握手,降低建立连接成本。对于从CDN下载图片速度帮助很大。

 3) 域名收敛:收敛域名至公司的主力CDN域名。

尽量将请求集中在少数几个域名下,以提高长连接的复用率.

 4)TCP调优:

无线网络特点是丢包率高、RT长,针对此特点可以针对性的TCP调优。

实施的方案:

调大初始拥塞控制窗口、关闭空闲slow-start、动态MSS、关闭TCP DF、去掉TCP时间戳

 5)报文缩减:逐步由json协议格式向类PB协议转换。

 

五.图片方面优化

图片是电商app使用场景中最多的元素,如何快速节省流量的下载和渲染图片是电商app都非常关注的。除了上面网络优化提的长连接,域名收敛等几点之外,手淘还建立图片的分级机制。

按分辨率,质量,锐化,格式四个纬度,对同一张图片生成了不同组合的衍生文件。

设置了一系列匹配规则,针对不同屏幕,不同机型处理能力,不同网络环境,配置出合适当前情况的图片大小质量,保证图片大小既节省又保证用户视觉体验。

手机淘宝性能优化

其中一个经验是当锐化程度高时,即使图片质量较低,图片色彩清晰度也都能让用户满意。

 

六.工欲善其事必先利其器

在整个手淘的启动优化过程中,系统的工具帮了我们很大的忙,Android的主要是自带的 TraceView工具,IOS 主要是Instruments自带的Time Profiler,System Trace等工具,它们都是数据采集和分析工具,主要用于分析应用程序中的hotspot,都非常强大。工具的具体使用方法不在本文论述范围内,但是这些工具都提供了程序中的所有线程使用状况,而且线程中的每一次的调用都可以看到具体的堆栈信息、耗时等详细信息。通过对这些调用的分析,就可以找到启动过程中相对耗时的调用。分析出具体的瓶颈点以后,就可以有针对性地进行具体优化了。

比如 手淘Android启动阶段以前有一个加密存储的模块,它会调用系统的SecretKeyFactory.getInstance()方法来生成加密的 key,我们是通过 TraceView 才发现这个函数调用会耗时300ms 以上,通过 TraceView看里面的调用堆栈发现它里面存在锁操作,所以比较耗时,找到这个瓶颈点之后,手淘Android调研了多种加密存储方式,最后换了一种比较轻量的加密存储模块,优化了该瓶颈点。

 

最后总结七大原则:

1.善用性能分析工具,建立监控体系

2.做好网络基础建设和网络调优

3.离线化,本地缓存

4.懒加载

5.任务分级,合理并行

6.在主线程移除多余操作

7.简化合并复杂视图

上一篇:闲扯DDD


下一篇:思辨领域模型--DDD≠数据库关系模型