在2014年12月19日~20日举行的ArchSummit北京2014大会上,腾讯即时通讯平台部技术总监范瑞彬做了题为《手机QQ的移动化实践之路》(幻灯片下载)的演讲,介绍了手机QQ在服务海量移动用户方面经历了的一些经验。
范瑞彬(hata fan),腾讯公司即时通讯平台部技术总监,T4专家。2004年加入腾讯,长期负责手机QQ后台整体建设,完整地经历了手机QQ从数千人在线到亿级在线的整个过程,见证了十多年来移动互联网服务的高速发展。目前主要负责QQ整体的接入平台建设,在海量分布式后台架构、IM系统设计、移动业务架构设计等方面积累了多年实践经验。
本文系根据演讲内容整理而成。
演讲主要涉及3个部分。第一,移动环境的特点。第二,针对移动环境的特点,如何做好接入?第三,架构设计理念方面的变化。
下图包含了云、管、端三个部分,多种终端通过多种网络访问云端的服务。上面红色部分是接入层,是首先会受到影响的。下面是逻辑存储、运营支撑和安全体系,这个系统目前终端同时在线过亿。终端每秒的请求量差不多千万,一天的请求量在数千亿的量级。
可以从三个方面看移动环境的特点。首先是移动网络,大家首先感觉是慢,而且流量又挺贵的。它还有很多种制式,差别也很大。还有终端的特点,相对PC来说手机终端资源(CPU、内存、电量等)是受限的,永远是不够用的。而且终端的平台很多,机型多,能力差异也非常大。还有一个很重要的特点就是移动性,可以随身携带,可以随时随地利用碎片化的时间,环境多变,使用频繁。
面对这些环境的变化,接入首先会受到影响,而接入又是所有服务的基石。所以在移动环境下面,提供高质量的接入服务非常重要。如果将接入比作开车,那首先要选择一条快速的路线,这就相当于路由调度策略。另外还需要有一辆好车,车要快,类似于数据传输加速。然而选了一条好的路线,也有了一辆快车,并不代表就能快速到达目的地,尤其是非WIFI接入时,新增了基站、大量新增的网源系统,非常复杂。这里面有一些规则需要了解,如果不了解的话可能这些就是坑,而遇到了坑可能会翻车,所以不能把它当成黑盒,所以需要熟悉路况。路况很复杂,车也很复杂,跑的过程当中难免会遇到异常,所以还得会修车,不能抛锚,这几点是接入的几个主要工作。
分布式接入,在南方、北方和中部选择了三个地区,各自部署了一个点,每个点也覆盖了三大运营商,这是基础工作。
这时还有一个问题,如果中小运营商用户也访问到在三大运营商部署的服务,会存在跨网访问,质量很差。所以又建设了一个内容加速机房,它有独立IP,而且是TCP互联,路由直达,这样中小运营商的质量可以得到明显改善。针对海外用户,最初在香港部署了一个点,后来又在全球各大洲,每个洲选择了一个点,海外用户就近访问加速点,通过加速点再访问国内的服务器。
部署是在不断优化的,调度也需要更精准的体现。所谓调度,无非就是说什么时候,哪些用户该连到哪些server。所以这里可以分用户、server、时间三个维度。比如说用户,细化到每个网关;server,把用户调度到质量较高的server上面去;时间比较好理解,因为移动网络经常有波动,需要快速地发现波动,并及时自动干预,把它调度走。
还有一个很常见的问题,就是频繁切换网络。用户可能每天都在不同运营商,不同的网络之间来回切换。连接的时候不用域名,直接用IP,那如何保证用户不管怎么样切换网络,都能连接到连到他应该连接的server上面呢?假如说用户第一次连某个网络时,他会使用本地默认列表,连到server时,如果server发现不是最优的,会及时纠正,下发一份新的server列表。开发团队干脆把用户最近使用的50个接入点统统缓存下来。
做完了调度相当于选择了一条快速路线,这是不够的,还要想办法造一辆快的车。
首先是不用域名,直接用IP。这样可以减少域名解析的开销,更重要的是,可以避免域名解析带来的各种故障,还可以减少一些被屏蔽和封掉的可能。
第二点是重用连接、预连接。比如说QQ里面发图的时候,其实用户还在选择图片的时候,会先把连接建立起来,而且用户传完图以后连接不会立即断掉,会维持一段时间,后面有批量图的时候可以继续使用,减少一次连接的时间可以减少几百毫秒。
第三点是精简协议和逻辑。
第四点是参数调优。比如说“拥塞窗口”(congestion window,CWND),server的操作系统默认是4,建议调大一点,可以调到10,这样可以减轻慢启动对传输带来的影响。还有最大传输单元(Maximum Transmission Unit,MTU),之前跟运营商的朋友交流,他们给的建议是不要大于1400,现在基本上都是按照这个策略来做的。还有重新传输超时(Retransmission Timeout, RTO),一般设3秒左右,系统默认值设的是1。
还有一点叫高带宽时延积环境,在这种环境下面会遇到带宽吃不满,存在浪费的问题。以前网络都是2G网络的功能机时代。当时传图片大部分用的都是单连接。最近几年,网络越来越多,种类也越来越多,而且网络也越来越好。所以系统也进行了改进,可以根据网络状况动态地选择合适的连接数。比如说经过理论分析以及实验验证,开发团队发现其实在WIFI、3G、4G比较好的网络下面传输大数据时,用双连接比单连接提升至少10%,而且越好的网络提升效果越明显。
不能简单地把移动网络环境当成黑核来处理,有些细节知识是需要了解的。
第一,要了解国内移动网关的一些设置,比如说它会限制某个包传输的大小,如果超过的话直接失败。之前跟设备厂商了解,华为很多网关设置的是10M,但是各家都不一样,也没有什么标准。还有网关很多时候对传输时间有限制,这个也是各家不一样的。了解了这些细节,肯定要很好地支持分片和断点续传,否则在某些地区可能会出问题。
第二,网关对很多标准的理解和实现,各家也是不一样的,尤其像影响比较大的,比如说对HTTP协议的理解和实现。比如说在HTTP的标准文档里面,提了一个range,但是没有强制去做,有的厂商支持的就不是太好。曾经遇到过一种情况,头部用到了range,在分片传输图片时,运营商网关把它过滤掉了,客户端就不知道下一次该从哪里发,所以可能又从第一片开始发,这种情况下,如果客户端没有做好相关保护,就非常危险,会大量的重传,用户流量会被大量消耗。这就是需要注意的地方,尽量不要在HTTP头部加一些字段,需要传一些信息的话,可以放在包体里面,自己解析和理解。
第三,tcp_tw_recycle。用户说网络是好的,但是连不上server。抓包分析发现,客户端三次握手的包已经发过来了,但是server没有回。这是什么问题呢?经过深入分析,研究了一下协议栈,以及一些参数设置,后来发现,假如tcp_tw_recycle是开启的,server会检查对端同一个网关IP发过来的包,时间是不是递增的,如果不是递增的可能会丢掉。但是移动网络环境下,这是很难保证的。关闭tcp_tw_recycle,问题就解决了。后来这成了外网接入层的标准配置。
第四,端口受限。有人反映某些地区的用户连server的某些端口连不上,或者是连接质量比较差。比如曾经发现香港数码通的用户连8080端口的质量非常差,很慢;还发现有些机场WIFI,比如说深圳机场WIFI,除了8080和43之外的断口都封掉了,用其他的端口用户也连不上。开发团队意识到,不应该被动地靠用户的反馈来发现问题和解决问题,所以建设了一套自动的系统,根据海量的数据去分析,根据分析结果,server在给客户端返回合适接入列表时,优先选择质量高的端口,而且也尽量注意端口搭配的多样性,这样可以提升接入质量。
最后看一下信令风暴。其实从09年开始,手机QQ这边每年会被运营商朋友拉过去一起探讨这个问题,双方本着互相理解、合作共赢的态度来对待这个问题。除了建立一些双方认可的虚拟消耗运算模型之外,双方还就移动业务达成了技术共识。比如说减少定时包,减少不必要的及时包,因为有些包真的不一定要非常及时。可以适当做一些缓存和合并。还有一点就是要有流控,万一客户端有BUG,大量的发包,这时候有压跨移动网络的可能,并不仅仅是数据网,它对电信网也有影响,所以server这时要有能力控制客户端发包的策略和频率,这样HTTP服务才能让人放心一点。
比如说业务用的是TCP长连接,但是请求有可能被劫持,可能会返回到奇怪的HTML页面,最常见的是WIFI的认证注册,这时需要及时准确地发现这些问题,展现出来提示用户。
有一种网络抖动叫先发后到,需要做一些保护。比如说要求客户端发包的时候一定要递增,而且即使进程被杀掉重新再起来,也要保证这次发包比上次大。借助这个大小能知道真实发包时间的先后顺序。
终端休眠,终端是为了省电,肯定有一些休眠策略,App为了应对这些策略,有一些自动唤醒机制,做一些自己想做的事。如果用Wakelock,拿到这个锁之后,系统再也进入不了休眠了,这个锁一般用两三秒就足够了,一定要慎重。
最后是App健康和智能检测。客户端不能保证百分之百不出问题,有时候确实有可能在一些小概率的情况下,存在异常的点,它有可能会触发一些频繁大量的发包策略。大量的发包会把用户的流量大量消耗掉,而且这还算轻的,更严重的是如果有较多用户都出现这样的问题,可能不是流量消耗的问题,而存在把移动网络压跨的可能,移动网络真的很脆弱。
《刑法》中有一条罪叫破坏通信罪,可以判三到七年,所以这种工作很危险,也是有责任的。压垮移动网络后果很严重,要想办法极早发现和干预。怎么办呢?server可以做一些准实时的流量消耗分析,如果发现在单位时间内用户流量超过某个异常值,就及时干预,而不是事后检查。比如可以把用户直接踢下线,或者更严重一点,直接让客户端的App自动自杀。
除了流量的问题,还有一些问题也是很隐蔽的,比如说用户的流量看起来没有太大变化。但是可能客户端有bug或者是设计不当,调用了几次后台操作,这个版本发出去的话,调用可能会增加好几倍甚至更多,后台的压力就非常大,于是又是过载保护,又是紧急扩容,这个也不是开发团队希望看到的,需要有更好的办法来解决它。比如可以分析这个版本,每个用户的使用频率。如果发现这个版本与上个版本相比,使用频率变化很大,多了很多,而且又没有提前报备,这里肯定有问题,就把这个问题抓出来,这些事情靠测试同学是不现实的,他很难测试到这些问题,这些问题需要技术同学自己想办法通过做智能数据分析来发现。
根据大量的实践,开发团队提炼出两个关键词:轻量交互和差异服务。
轻量交互,其实核心思想就是节省,主要思想是从协议层面以及逻辑层面做一些精简、合并、压缩、消峰、异步等等。
减少交互步骤。客户端一次请求,尽量把信息都拿下去,后台也尽量把相关的信息都加进去,完整地带下去,减少交互步骤。这里要求后台要多主动地做一些聚合工作,一些协议要重新设计。
精简交互信息,尽量减少每一次传输过程中的信息。有个原则,就是不用的信息尽量不要拉,这里要求开发团队在协议设计的时候要非常灵活和细致,要支持增量更新和同步逻辑。
复用包头。一般做协议设计的时候有包头和包体,包头里面放一些账号信息、身份凭证,还有版本信息。尤其随着现在安全压力越来越大,形势越来越严峻,身份凭证可能会越来越长。其实这些信息没必要每次都带,可以在接入server时做一些缓存,后面的包就不需要这些信息了,这样的话每个包可以减少几十个字节,甚至更可观。这样算起来收益是很大的,不光能帮用户省流量,因为传的内容烧,也能加快速度,对体验也有改善,勿以善小而不为。
智能合并压缩。这里需要对业务逻辑有深入的了解。不是所有的包一定要最快响应,可以请求分一下优先级,哪些是需要及时响应的,一定要及时保证。哪些是可以降级的,不需要很及时。可以把大量的不需要及时响应的包做一些延迟,这个延迟不仅是为了解决运营商的消耗问题,延迟以后可以做压缩。当然具体延迟多久,可能要根据具体业务的场景来看。
客户端异步削峰。还是细分问题,把一些不重要的包或者是当前这个不是立即需要的可以往后放,先让用户快点接入进来。同样,客户端也需要注意不要把UI绘制跟存储放在一个线程里面做,避免卡顿。
可以把差异服务理解成个性化服务,针对网络情况和终端优化应用。下面具体看看。
怎么做好预拉取。比如说QQ会拉消息,拉过来的一堆消息里面可能有一些是图片消息,一开始看到这些图片消息只是缩略图。那何时去下载这些缩略图的原图呢?如果说等用户点了之后再去下载,自然大家会觉得这个很慢,体验不好。那提前下载该怎么做呢?这里要细致和全面一点。比如说可能要细分网络状况,在非WIFI网络下面流量是很贵的。如果把原图下载了下来,用户也不看,这样流量就浪费了,这浪费的就是钱,肯定不合适。那怎么办呢?可以设计一个算法,类似于银行家算法,给每个用户分配一个配额。比如说有500K的配额,预拉取一张原图,比如100K,如果用户看了原图,配额不变;如果用户后来并没有看,则把配额减去100K,凡是预拉取了而不看的配额都减掉,配额减到零就不会再做预拉取了,避免盲目下载造成大量的流量消耗。
在WIFI情况下,是不是可以简单地全下载下来呢?这样也不好。虽然用户的流量在WIFI下基本不收费,但是腾讯后台的出口带宽很贵。尤其是图片下载消耗非常大,这个钱是很多的。怎么办呢?可以根据业务场景做细分。比如把图片分为群图和C2C图,就是好友之间点对点的图。分析发现,C2C图相对是比较重要的,用户点看原图的概率非常大。同时C2C图占比相对来说又是非常小的,因为大部分是群图。所以C2C图可以预拉取。群图还是采用类似于银行家算法的方式进行管控。
预拉取思路很简单,但是要做好,可能还需要很细致地结合网络状况,结合用户状况和业务场景做细致全面的细分,这样才能在用户体验,以及服务成本和用户成本之间找到一个恰当的平衡。
信息繁简不一。很多信息应该分类归档,针对一些好终端、好网络,尽量返回一次很好的信息,反之只给它简化版。
多种套图规格。需要根据多种屏幕来抽象和简化出几种通用的图片规格,而且可以根据不同网络状况来定每种规格的压缩率。
终端是该轻还是重。到了手机时代,因为手机本身能力比较弱,而且产品还经常要求做一些跨终端的一致体验,很多东西必须放在云端统一处理才可以。大部分场景下是轻终端重后台,具体要看业务场景。比如说有些游戏,以前PC时代为了防止PC客户端作弊,很多信息都是客户端直接给server,一律由server统一去算。但是在手机游戏上面,为了减少信息传递以及减少交互次数,很可能会在终端也做适当的计算,把计算结果再发给server,在这种特殊的场景下面,在这些逻辑方面可能终端做的更重一些。所以这个问题有普遍性,也有特殊性,要具体分析、具体看,深入理解业务场景和逻辑。
能不差异的地方就不差异,考虑全面些。设计的时候要考虑全面,要把各种平台、各种网络都考虑到。在选择压缩算法、加密算法、图片格式和文件格式时,这些东西能通用的还是尽量通用,不要给自己找麻烦。如果有些地方没法统一,必须要差异,这里要抽象简化,简化为几大类,而且这个差异点尽量使后台可调可控。
终端版本信息管理,终端运营配置管理。需要把终端版本的各种信息记录下来,然后才可以根据这些信息,再加上用户的信息灵活调整配置给不同用户更好的体验。可以根据不同地区、不同网络、不同版本、不同运营商和不同号码,以及根据不同的CPU、不同的摄象头、不同的内存,给用户下发不同的闪屏和不同的插件,这是基础能力的建设。
范瑞彬最后还用一句话做了总结:“从实践中来,到实践中去”。