有种速度让你望尘莫及 | 手机QQ及Qzone速度优化实践new
qbeg3537
8年前
<h2>导语</h2> <p>移动互联网发展那么快,运维技术也要适应业务的变化啊,这次小编找了腾讯牛人介绍的手机QQ和手机Qzone的速度优化实践。</p> <p>我们坚信不同垂直领域的运维分工会越来越不同,如何能在不同的业务形态上,利用运维技术和数据为业务带来更大的价值,将是我们下一步探索的重点方向。</p> <h2>1. 关于用户等待时间</h2> <p>对用户来说,最直观的感受就是APP的等待时间,所以我们首先要分析清楚APP到底在哪里让用户等待,耗时在哪里。</p> <p>等待时间无非就以下三个:</p> <p>· Server处理耗时</p> <p>· 网络传输耗时</p> <p>· 客户端数据处理/UI渲染耗时</p> <p>QQ/Qzone等产品由于已经有多年的Server端优化,大部分数据都是直接读写nosql数据库,接口耗时基本都在30-120ms,优化Server实际的收益并不会很大。</p> <p>下面主要介绍后两个方向上的优化实践。</p> <h2>2. 网络传输</h2> <p>首先我们需要统计数据在网络传输的耗时情况,才能知道优化网络传输有多少价值</p> <h3>2.1 网络传输耗时统计</h3> <p>网络耗时通过TCP协议的三次握手在服务端进行统计,优点是简单快速低成本,具体方案如下:</p> <ol> <li>记录下第一次握手时服务端收到SYNC包的时间Time1</li> <li>记录下第三次握手时服务端收到的ACK包时间Time2</li> <li>两个时间之差即是网络往返耗时RT(Time2-Time1)(见图2.1)</li> </ol> <p style="text-align:center"><img src="https://simg.open-open.com/show/95696b8e0a592624219d8d66c703b4bf.png"></p> <p>图2.1 从服务端测网络延时</p> <p>通过实际数据统计,在不跨网访问的情况下(信号正常):</p> <p>· 4G耗时约30-100ms</p> <p>· 3G耗时约 200-400ms</p> <p>从速度结果上看,目前主流的3G/4G网速还是相当不错的,但是由于移动网络的复杂性,从QQ和空间的业务返回码监控上还是发现有不少问题:</p> <p>· 跨网访问</p> <p>· 跨地区访问</p> <p>· 某些小运营商劫持等</p> <p>下面分享下手机Qzone在接入组件的优化策略</p> <h3>2.2 手机Qzone WNS接入策略</h3> <p>简介:WNS,手机QQ空间APP到服务端通信框架,支持tcp、http协议</p> <p>2.2.1使用私有协议直接IP长连接访问(图2.2)</p> <p>优点:</p> <p>· 减少DNS请求耗时</p> <p>· 避免DNS域名劫持</p> <p>· 单个连接并发多个数据请求减少连接数的开销(相对http)</p> <p>· 私服协议加密安全;</p> <p>缺点:由于不走域名,首次连接需要额外的策略来找到合适的接入点,并且需要有重定向能力</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/f96699ce6c7fa60cbd75ee751f59897c.jpg"></p> <p style="text-align: center;">图2.2 私有协议直接IP长连接</p> <p>2.2.2 首次连接策略</p> <p>世界上最遥远的距离就是你在联通,而我在电信。在复杂的移动网络环境下,我们需要优化网络的接入策略避免跨网/跨地区访问。</p> <p>使用移动网络时我们先识别用户的运营商,同时起4个连接,多个接入IP+多个端口+2种协议,再同时使用2种协议和多个端口是为了避免有些本地运营商的限制,使用第一个连接上的连接(见图2.3)</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/11cff3880fd55e8a41cfe64bf7f5404e.jpg"></p> <p style="text-align: center;">图2.3 首次并发尝试连接</p> <p>使用WIFI的用户首次连接会优先使用域名尝试连接。</p> <p>当上面策略都连不上时客户端会运行打分策略,使用备份IP列表连上一个速度最快的接入。</p> <p>腾讯拥有国内大量的CDN节点,即使是偏远地区也可以通过CDN节点接入做为代理!</p> <p>优点:多种首次连接策略能有效的保证用户最大可能的先连上服务器,这在复杂的移动网络中特别重要!</p> <p>缺点:首次连接有额外开销;连接上不一定是最优的接入点;使用CDN节点做为代理接入成本较高</p> <p>2.2.3 最优接入&重定向</p> <p>连接上之后服务端通过GSLB IP库识别用户的出口IP,如果发现用户的接入不是最优的接入,通过大数据分析该用户在某个时段最应该使用的接入点,会下发重定向指令,让客户端连接到最优的服务端接入IP,WIFI下还会缓存住SSID和接入IP。</p> <p>优点:让用户能就近/最优接入,减少网络的耗时</p> <p>缺点:少部分用户首次使用需要连接2次服务器;</p> <p>2.2.4 使用字典做数据压缩</p> <p>减少带宽开销;安全</p> <p>2.2.5 心跳</p> <p>避免长连接断开</p> <p>2.2.6 单连接并发请求</p> <p>相对多连接单请求的传统HTTP模式(HTTP 2.0之前),用单连接可以大大减少客户端和服务端开销</p> <h3>结论</h3> <p>移动网络上我们能做的优化无非就是减少连接,减少请求,避免跨网跨区,优化协议。而随着4G/光纤的快速发展,以后越来越多用户在网络上的耗时会越来越少,意味着我们网络策略上的优化效果收益也会越来越低,这时我们把目光投向终端。</p> <h2>3. 终端耗时</h2> <p>同上,首先需要确认终端的耗时情况以确认优化预期和目标。</p> <p>通过在客户端埋点的上报监控,发现手机Qzone某个灰度版本用户一些操作之后3秒以上没响应比率最高达30%;手机QQ某个灰度版本由于UI问题导致画面掉帧比率约15%,在投诉的问题分类中,卡、慢、卡顿投诉量长期居前三甲。</p> <p>可以得出这样的结论:终端的问题很严重,而且跟用户操作体验直接相关!</p> <h3>3.1 Android/IOS系统背景</h3> <p>既然是想优化移动客户端,那对于操作系统(Android和IOS)需要有个基本的了解,两者都是基于UNIX/LINUX开发的系统,对于运维人员来说很多概念都很好理解。</p> <p>其中比较重要的一条设计理念是:Android和IOS都能进行多线程开发,其中有一个是主线程也称UI线程,UI线程是唯一有权限操作用户UI的线程,如果用户在操作有体验上的问题,那肯定是因为主线程被堵塞或没有足够的运行资源。所以从主线程的监控和系统资源的占用入手。</p> <h3>3.2 监控的策略</h3> <p>怎么判断终端出现卡慢等性能问题呢?通过上面对andoid和ios的背景介绍,我们的目标放在主线程的监控上,这边主要有2种监控策略:</p> <ol> <li>监控函数间调用耗时<br> 当主线程调用函数调用超过N秒时,主线程处于等待堵塞状态,用户所有UI行为暂停,所以认为终端出现卡的情况。 <p>缺点:无法准确反应用户的体验</p> <p>优点:实现成本低,开销低</p> </li> <li>监控屏幕FPS,监控掉帧数<br> 当用户操作时发生页面掉帧时,认为用户发生卡慢或卡顿(如图3-1) <p>优点:真实反应用户的体验,而且能对卡慢卡顿的体验分级,如分为短卡、长卡</p> <p>缺点:有额外的FPS监控开销,经过测试该开销大概占整个APP开销的2%</p> </li> </ol> <p style="text-align: center;"><img src="https://simg.open-open.com/show/ff92060c94761abe61cdb2bd30fa52f6.jpg"></p> <p style="text-align: center;">如图3-1监控屏幕FPS的次数</p> <h3>3.3 堆栈的采集</h3> <p>监控的策略有,接下来应该考虑怎样配合监控策略,把“案发现场”的数据获取出来并上报至服务端。</p> <p>“案发现场”数据除了系统资源,如CPU、内存等,最重要的一定是代码的执行堆栈数据。由于移动终端性能资源有限,在采集堆栈数据的时候要非常注意对系统的影响,所以需要定好触发采集堆栈的时机,这边主要也有2种采集方案:</p> <p>3.3.1 开启额外的线程记录主线程堆栈</p> <p>额外启动一个子线程,子线程记录着主线程的堆栈数据,当发生卡顿的时候从该线程获取到堆栈数据,优点是只需要引入一个很小的SDK包,而且无视版本的编译方法和虚拟机。获取堆栈的策略也分为 消极策略和积极策略</p> <ol> <li> <p>消极策略:</p> <p>认为卡慢卡顿的问题在短时间内只会发生一次,如果错过了将无法获取到真实的现场堆栈。</p> <p>该策略的做法是:子线程时刻获取着主线程的堆栈,当主线程发生问题时,通过发生问题的开始时间戳和结束时间戳,在子线程获取到案发时的堆栈数据(如图3-2)</p> <p>缺点:需要子线程时刻记录主线程堆栈,开销大</p> <p>优点:获取到的堆栈数据准确</p> </li> </ol> <p style="text-align:center"><img src="https://simg.open-open.com/show/4256bee1db4d93c969c97c6fab877145.jpg"></p> <p style="text-align: center;">图3-1监控主线程函数调用耗时</p> <ol> <li> <p>积极策略:</p> <p>认为卡慢卡顿的问题在短时间内会发生几次或持续发生一段时间。</p> <p>该策略的做法是:当主线程发生问题时,激活子线程获取堆栈,在接下来的N秒内在子线程获取X个堆栈</p> <p>缺点:堆栈有随机性,获取到的堆栈是案发后的堆栈</p> <p>优点:额外开销极少,对APP基本没影响</p> </li> </ol> <p>3.3.2 在编译阶段打桩/嵌入埋点</p> <p>通过在编译阶段使用工具在每个函数调用点加入耗时统计函数</p> <p>缺点:增加APP包大小,经过测试约增加APP10~20%的包大小,而且不同编译方法和虚拟机需要不同的工具支持打桩嵌入;缺少系统调用数据</p> <p>优点:无需运行时的额外线程额外开销</p> <p>2种方案都各有优点各有可取之处,但由于产品对包大小有严格限制,目前在QQ和Qzone主要采用方案1</p> <h2>3.4 大数据聚类分析</h2> <p>前面提到,方案1的消极策略对终端性能影响较大,但是积极策略获取到的数据有随机性,即客户端无法精确的捕获到问题堆栈。</p> <p>而目前我们主要采用积极策略+大数据聚类分析的方法来分析问题。这一方案的基本思想是如果一段逻辑代码真的有性能问题,那大多数用户都发生。</p> <p>所以我们采用对堆栈数据做聚类分析的方法,将能形成数据规模的堆栈找出来,过滤掉偶尔由于随机性获取到的无关堆栈。</p> <p>对堆栈的聚类统计上,我们主要通过构建CT(ClimbingTree)来解决。</p> <p>ClimbingTree是内部叫法,主要思路是通过堆栈生成堆栈树,并利用海量数据加权计算(主要是函数耗时)到树上,最后根据权重将同层节点运行从左到右进行排序,并将设定阈值以下的节点运行剪枝。</p> <p>ClimbingTree的特点是同一父节点的子节点权重大小从左到右递减</p> <h3>3.4.1 构建CT(ClimbingTree)图</h3> <p>先将一个用户的一个上报堆栈数据先进行预处理,包括解密文件、翻译堆栈函数、格式化堆栈、过滤掉无关数据等步骤,最终生成一条业务函数调用关系链。</p> <p>根据调用关系,合并同个用户多个调用关系链,相同节点耗时相加,并按每个树节点的耗时从左到右排序,生成函数调用关系树(见图3-3)</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/4835819e4dbd42182f19b68b7fa446f8.jpg"></p> <p style="text-align: center;">图3-3 函数调用关系树</p> <p>合并多个用户的调用关系树,剪掉阈值下低权重的节点树枝,就可以生成CT(ClimbingTree)。这棵树里就包含了所有问题堆栈的数据聚集,并且问题严重程度从左到右排序(见图3-4)。</p> <p>图假设每个节点耗时为1s,那么CT里A-B-C这条调用关系链很有可能就是问题所在的函数调用关系链(因为C节点对父节点的耗时占比为:2/4=50%)</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/f1c4ce54f538636f4c5eb4bd462ed6c0.jpg"></p> <p style="text-align: center;">图3-4 CT图</p> <p>CT的优点在于将海量的数据聚集统计到少量的森林数据节点里(约压缩90%-95%的数据量)</p> <p>由于左子节点一定比右节点耗时长,所以往往左子节点即是影响父节点的问题所在,通过分析左子节点占父节点的耗时占比可以得到最根源的耗时函数所在(见图3-4、图3-5)</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/f80f892f2e738fd6eddc6b2e794cabd1.jpg"></p> <p style="text-align: center;">图3-5 寻找最根源的耗时函数节点</p> <h3>3.5 终端常见性能问题总结</h3> <p>最常见的问题在主线程做长耗时操作,如</p> <p>· 数据库操作</p> <p>· 网络连接等待</p> <p>· 网络数据等待</p> <p>· 复杂逻辑计算</p> <p>· SD卡检查或读写</p> <p>常用的优化方法:</p> <p>使用子线程做异步操作,如数据库的写操作,配置网络拉取等可预加载的提前预加载,例如利用APP打开等待首页的时间打开网络长连接,对视频音频数据做预加载等</p> <p>能延后处理的异步延后处理,如SD卡检查,异步发消息等</p> <h3>3.6 案例&效果</h3> <ol> <li>QQ IOS某几个版本经过优化之后的卡慢投诉数据:</li> </ol> <p style="text-align: center;"><img src="https://simg.open-open.com/show/126935c7170bca5d86c7f49d729477d0.jpg"></p> <p>Qzone Android:某几个版本的卡慢发生率(卡慢发生率=卡慢发生人数/使用人数)</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/c2e2f9affe2d0e5631f8fada7ae8cf7e.jpg"></p> <h2>4.总结</h2> <p>在高速发展的移动互联网时代,运维技术要适应业务的变化,本文介绍的手机QQ和手机Qzone的速度优化实践,是腾讯运维利用大数据技术为业务创造价值的小案例。</p> <p>我们坚信随着运维岗位的发展,不同垂直领域的运维分工也会随之而生,如何能在不同的业务形态上,利用运维技术和数据为业务带来更大的价值,用数据说话让数据发声,将是我们下一步探索的重点方向。</p> <p> </p> <p> </p> <p>来自:http://www.yunweipai.com/archives/9203.html</p> <p> </p>