扫码打开虎嗅APP
本文首发于InfoQ微信公众号,ID:infoqchina
在京东上季度的财报中,无线端(包括移动端和微信等其他无线平台)占比已经超过72%,这也给京东无线业务部带来了巨大的压力。今年,京东618主会场首次全面采用个性化策略,同时,618期间的一系列促销活动,预计将为后端带来超出日常20倍左右的流量洪峰,这都给无线业务部带来了更大的挑战。为了迎接挑战,防止突发情况的发生,无线技术团队从演习、监控到预案,制定了全方位的备战计划。
受访嘉宾简介:
赵云霄,京东商城无线业务部首席架构师。2011年加入京东进入无线团队,负责服务端的开发与架构设计工作。见证并参与了京东无线从小到大,由弱到强的整个过程。五年间,带领团队完成了无线服务端的两次重大架构升级,无线服务端从一个简单的Web应用进化成为支撑每天几十亿级访问的分布式系统。目前负责京东无线网关系统的研发工作。
陈保安,京东商城无线业务部研发高级经理。从事研发工作十年,2011年加入京东。目前主要负责无线核心业务(搜索、商品、购物车、结算、收银台)的后端研发工作,多次带领团队进行系统架构升级和多次大促经历磨练,为京东无线核心系统后端服务稳定性打下坚实基础,支撑无线千万级的活跃用户和JD过半的订单占比。
InfoQ:为了备战今年的618大促,京东做了很多演习。请具体介绍一下移动端演习的内容、分类和流程,以及演习时的模拟数据是怎样设定的。
赵云霄:大促前我们都会有一系列的演习,一般情况下,无线端会在大促前至少半个月开始演习,具体的时间由演习的不同性质来决定。当然我们的演习不可能只是一轮,一般是多轮的演习,具体几轮视情况而定。
做演习的目的,一方面是测试系统所能承受流量的能力;另一方面是,测试在某些环节出现问题时,我们切换预案的执行效率如何。这两方面同时也是我们在做演习时的主要内容,所以演习相应地分为压力测试和预案切换两类。
压力测试是基于工具的,用来测试我们对流量的承受能力,包括单机和系统整个集群的承受能力。压力测试一般分为两种,一种是工具测试,一种是线上流量。我们会把线上的流量引到其他一些少数的机器上去测试单机的性能。
预案切换类的测试,就是对预案进行演练。预案演练是指,有一些预案虽然已经定好了在出现问题怎样去执行,但在现实的执行过程中仍有可能会出问题,所以我们需要提前去对预案进行演练。这类演习一般都是提前一个月或者一个多月先做一轮,先暴露出一些问题,然后根据暴露的问题来分析是否有必要再做一轮。如果再做了一轮还有问题,那么我们还会调整,再演习。但是一般情况下,不超过三轮我们就会发现很多问题,包括大数据要解决的问题。
演习的数据有两种,一种是线上流量,一种是造数。
线上流量,一般就是使用线上的数据,例如将一个集群中的十台机器摘掉九台,看看一台能不能支撑,以此来测试单机的性能。
造数是指由我们专门的测试团队去造测试数据。但是这样一来,一些写操作,会引入一些脏数据。在造测试数据时,我们会尽量把SKU分散开,预估热点SKU的数量,来做更真实的模拟。同时,我们会在压测的请求URL中增加一个标识,来区分正常业务和压测数据,以便后期清洗这些脏数据。
陈保安:我重点从下单之前和下单之后这两个环节说一下模拟数据。
一是下单之前的模拟数据。我们通过测试,把线上的日志数据抓下来之后做回放,尽可能模拟真实用户的请求。然后将它放大几倍或者几十倍去做压测。这类数据所进行的操作分为两种,一种是读,另一种就是刚才提到的写操作。读操作的数据可以无限放大,因为这种东西不会对数据产生干扰。而写操作的数据需要在最后清理出来,以免对真实数据造成影响。因此会设置标识来便于后期清洗脏数据。
二是下单之后的环节的模拟数据。在有些场景下,比如在我们整个京东的“军演”过程中,使用的是线上的数据。它模拟的是我们下单之后,后端所有的支付、配送等所有的系统的压力。我们会在“军演”时“憋单”,使得管道里面存20万单或者更多,然后一下把订单下传下去,模拟出给整个后端环节的压力。
InfoQ:在618的期间的数据跟平时可能会有些不同,例如某些热销产品,数据变化较大,针对这种情况是不是会做一些特殊的处理?
陈保安:是的。618期间有一些数据会过热,尤其是一些促销力度过大的商品相关的数据。我们在演习的时也会去模拟这种数据。例如,拿线上50万或300万的数据去进行模拟时,我们会将其中50到100个商品的流量放得更大一些,来模拟部分商品热度较高的情况。我们还会测试在过热的情况下,例如一个商品受到了极限的访问,甚至达到整体的访问量那么大以后,我们的系统会不会有更好的处理。
赵云霄:因为过热的商品会造成访问数据集中在某一片缓存上,这有可能会暴露出系统设计上的问题。我们会通过技术的手段解决这种问题,然后将测试数据集中在上面,来看测试效果。
InfoQ:那方便说一下具体采用了哪些技术手段吗?
陈保安:我们会对热点数据做更多的本地化的缓存。例如单品页,它整个核心流程访问量最大,所以我们对单品页设有多级缓存来扛单品页的访问。通过CDN来扛外网流量的访问,主要适用APP的访问,另外nginx的共享缓存也会增加热点数据的缓存,因为有一些内网的调用不走CDN,第三方面在java进程堆内存中增加热点缓存,这一层的缓存时间较长一些,透传过来的流量会对上游基础服务做一个保护,所以一级一级这么去保护,避免某些爆款商品拖垮整体服务。
赵云霄:总得来说就是,设置多级缓存,同时尽量让第三方缓存的请求变得更散。
InfoQ:网络的复杂情况给移动端带来了很多问题。为了保障用户的最佳体验,京东做了很多适配工作,并在接口层面做了做了相应的设计。请您具体讲解一下适配的标准,以及接口的设计根据618大促的需求做了哪些改变。
陈保安:因为网络的复杂情况而带来的这些问题主要是由于手机端与PC有着不一样的特性。
首先,从网络流量和耗电量来看,图片加载对手机的消耗比较大。而从进到首页到后端搜索,再到商品详情,我们展现给用户更多的就是图片。所以,我们对图片会重点处理:根据不同的分辨率、不同的网络类型、不同的手机系统版本(安卓4.X版本和之前的版本区别较大),指定了相应的标准。这里是有一个比较大的escape标准东西,就是说有一个成熟的表单,它是由产品人员做了很多次测试得出的,在什么样的位置上,图片适配采用什么样的大小尺寸都有标准。
第二是,PC端关于价格、商家信息、状态跟踪,包括一些库存有一些信息,很多都是异步加载出来的。PC端的页面呈现给用户的信息可以在第一时间加载出来。然而手机端不一样。因为网络环境比较复杂,有可能这一秒有网,下一秒走到角落里可能就变成了弱网,甚至没有网了。这种情况下去创建更多的连接,成本是比较高的。而京东的单品页因为垂直的频道比较多,所以会更加复杂,虽然仅仅是一个单品页,但是它聚合了我们后端近50个基础服务。针对手机端,我们不会在单品页把数据异步下发,而是由后端聚合之后一次下发给客户端,这样就减少了建立链接的成本。
这一次618我们做的比较大的改动,就是规则的识别下发给了客户端。比如,刚刚提到的图片的识别规则原来是在后端去处理的,要根据手机的分辨率、网络类型、机器的版本去做适配,这样一来就涉及到静态化的数据,使得利用率变得非常非常低了。所以这一次我把这规则下放给了客户端,客户端只需要告诉后端是安卓的哪个版本,后台会给它下发统一标准的数据。而规则是动态下发给客户端的,比如说打开客户端以后,后端就把规则下发给了客户端。这样一来,后端就不需要再去根据分辨率、网络类型等去做适配,而是由客户端去做适配工作。
具体的下发的规则是统一的,包括在2G、3G等网络情况下分别对图片有怎样的要求。这一点是根据分辨率来固定相应的范围的,不是所有的范围,否则规则会太多。
赵云霄:总得来说是三点:
根据图片不同的位置,采取不同的适配标准。例如单品页商品展示的图片会比较高清。
Sever端的接口设计异于PC端的ajax异步加载。尽可能通过后端把数据聚合下发,减少客户端和后端频繁创建链接的过程。
单品页图片适配规则可动态变化。这是无线端针对618大促做的比较大的改动,单品页图片适配规则下发到客户端来执行,规则是动态可变化的。这使得后端不需要依赖手机的网络类型、系统版本等信息,可以极大地提高后端的Cache命中率。
InfoQ:京东曾提到,在系统升级的过程中,会尽量减少强依赖,将强依赖尽量转化成弱依赖,并不是直接依赖于服务。能否举例说明减少了哪些强依赖,是如何将强依赖尽量转化成弱依赖的。
陈保安:强依赖转变成这弱依赖,或者说尽量不依赖,就是说我们对这于实时性要求不高的,像商品的信息,包括图片、特殊属性、详情、商家等信息,以前可能是完全依赖于基础服务的,现在会把它的一些数据异构并存储下来。在发生变化时,通过管道MQ去通知做出一些变更,达到最终不会实质依赖基础服务去做商品聚合展示的目的。所以现在,其实是间接依赖。因为这虽然不是实时,但是是通过异步的方式给我的。而像价格、库存等变化非常频繁的数据,依旧是实时依赖。
还有比如说在下单之后,或者是在支付环节,会涉及到DB。而DB相关的数据,我们现在也是通过异步的方式落地的。因为这个说白了实质性要求没那么高,无线收银台可以不完全依赖DB,更多地依赖实时用户会话的缓存来于第三方支付机构进行交互。这也是因为在去年双十一的过程中,DB遇到了一些麻烦,主要原因是连接数比较多,所以这从强依赖变成了弱依赖。
赵云霄:其实像京东的系统,是一个完备的包括所有业务的系统,是一个完全的服务化的系统。哪些是必须看成强依赖,哪些必须看出弱依赖,在我看来这个东西没法去区分。
京东有几百上千个服务,我们要去梳理这些东西,比如说哪些东西没有必要直接同步的去调用它,让它影响我们,我们会去把这些东西梳理出来。现在的套路,要不是异步化,要不就像保安说的有一些地方我可以用空间去换取更好的交互,所以要么是采用中间件,要么是异构一份数据到缓存中。
那么所谓减少依赖都是在正常服务不可用的极端情况下可以去考虑的,在正常的服务化系统之间的交互,我们还是尽量保证专门的系统去做其专门的事。例如,在平时,我们会去依赖A、依赖B、依赖C,而且还会调度它们,但是我们还会有一个异步方案,在特殊情况下,比如说在流量非常大的时候,去切换到这个方案上,这个方案对后端压力比较小。
所以我认为没有必要刻意总结哪些强依赖、哪些是弱依赖。在一个比较庞大复杂的服务系统中,你没有太多办法要求别人的系统去做一个什么什么事,而我们的系统也要配合别人的系统去工作,所以这个复杂就会更高。所以我们只能想办法,各自做一些在极端情况下能保护后端的方式,这就是我们减少依赖的目的,也是遵循了前端保护后端的通用原则。
InfoQ:那么也就是说在618期间流量比较大时,可能会做出一些取舍,比如用空间去换取交互效果。那么在大促结束之后,会不会换一套方案把之前做的牺牲再换回来?
赵云霄:这是有可能的。因为在严谨的系统设计中都会有备选,在特殊情况下必须用空间去换取想要的效果,但是日常的流量情况不需要牺牲额外的空间。既要节省成本,又要保证正常的交互。另外,就像刚才提到的很多弱依赖的场景其实是个别情况,在大部分交易流程中,很多依赖还是实时的。把需要实时反馈的数据转换成弱依赖,实际上是我们做出的妥协。所有的这种妥协,在回归正常情况时,我们都有可能收回。
陈保安:做出妥协是非常必要的,领导曾说,我们虽然要依赖一些基础服务,但是基础服务真的挂了的时候,自己还要保证能活,这就是我们的最终目标,就是说要在基础服务出现问题的时候,我们能够有办法快速地去解决问题,而不是处于死等状态。
赵云霄:任何一个大型在线系统,它的主干要是最强壮的。我们可以减少分支上无关紧要的东西,来保护最重要的部分免受大流量的破坏,让它处于安全的保护之内,能提供正常服务。同时,由于用户体验非常重要,又涉及到京东很多用户,所有我们会多考虑出20%,比如考虑流量达到120%的时候要做出什么方案来保护它。
InfoQ:这些预案都是来处理特殊情况的,而在实际的大促过程中,为了保证万无一失,京东还做了很多监控工具和监控平台,那么京东都是从哪些纬度来进行监控的?移动端的监控平台有哪些?具体采用了什么技术?
赵云霄:事实上,在刚起步时,我们也缺少监控,经常半夜被叫醒处理技术问题。后来我们逐渐意识到,监控系统跟核心系统是同等重要,应当把监控系统看做正常业务系统的一部分。比如说,要新上一个业务系统,那么监控系统就占50%,没有监控系统就不可以上线。
从无线端来看,监控系统是多维度的。从底层的操作系统的各项指标,到各个层面的业务系统,再到网络都需要监控。
这些监控都是非常必要的,比如业务监控,有时候业务表面上是存活的,但是业务不正常,有可能出现很多逻辑上的问题,所以移动端还有对订单量、购物车、搜索等方面的监控,这些监控是业务指标级别的,也是应用层面的。我们有对应用主动调用的检测,不同的VIP进来,这就是从应用层面的存活激活,还有一些其他。各个团队如果感觉这应用不够,还会自己添加一些小的应用系统跑在机器上去监控。
另外还有对运维、云平台和网络层面的监控,这些监控一起形成了一个比较立体的监控系统,从底层到最上层都有监控。
目前,移动端涉及到的监控平台有以下几个:
核心业务监控(cpm平台)。主要有三个核心监控模块,依赖基础服务的返回码错误监控,依赖基础服务的异常监控和收银台全方位(机房、渠道、接入方、银行等维度)的数据监控。
monitor.m.jd.com:承担无线运维主要的监控入口,包括一些核心业务指标以及服务器基础监控等。分钟级别的监控,第一时间对业务以及可用率抖动进行告警。
网关、httpdns探测系统——prism.m.jd.com:主要承担网关、httpdns的服务器存活监控和网关连接池实时监控。监控系统每分钟探测自动化部署中这两个应用的所有服务器状态并以图形化的界面展示出来,只要连续两次探测不存活就会报警,如果没有及时修复,会持续报警,直到正常。实时监控网关连接池,根据它可随时调整连接池参数。
爱马仕监控平台——hermes.m.jd.com,承担网关全量接口的可用率、性能、调用次数监控及短信报警。同时,提供机房内外网、服务器IP、省份、运营商、客户端版本等各种维度按需组合的监控。
ZKCloud——zk.m.jd.com,为接入ZooKeeper用户提供可视化操作与详细操作日志,提供zk节点存活监控、各项指标性能监控,报警维度有短信、邮件、咚咚。
建设监控系统也有其相应的监控原则,例如监控一定要报警,允许偶尔误报,但不能不报。报警是多通道的,报警方式可以是短信、微信、邮件等。而且,报警至少要有两个人以上的接受人。
所用的监控技术,业内用的都差不多。我们主要就是埋点数据的升级,比如说在最基本的操作系统层面的监控会去采集利用相关文件,查看它的CPU、内存,在应用层面也会埋很多的点去上报这些数据。在获得数据后,有专门的团队来进行实时的数据分析,用最快的速度分析出结果,需要报警的话再走报警通道。对于重要的URL或者重要的请求,有探索工具来适配我们所希望的结果,如果探索不到这些结果,那么系统可能就有问题。总得来说,所用的技术就是数据实时分析和主动探测。
InfoQ:刚才提到,京东的监控做得非常立体,有很多团队去做。那么有没有统一的管理,或者说一些原则?有没有专门的人去对监控系统做审查?
赵云霄:监控点的加入是渗透在系统的设计中的。例如,系统的初期就应该对业务指标的数据进行监控,这是一个上线之前的规则。我们会定期做考察,如果有些该设置埋点的地方没有设,那么QA人员会做处理。
埋点的原则主要有以下四点:
资源调用处(接口、缓存、DB)必须埋点;
埋点必须可动态关闭(通过配置下发);
数据收集类的埋点必须通过多层的代码review;
埋点数据收集不能影响系统性能,对埋点的SDK要有性能测试报告才可以使用。
InfoQ:也就是说开发人员也要负责运维人员的监控环节吗?开发人员需要跟踪一段时间,来交接监控系统吗?
赵云霄:是的,而且我们的运维有研发能力,这是对互联网研发人员一个最基本的要求。
陈保安:各个团队做的职责不一样。比如说各个机房的流量分配运维更偏向于网络层、包括服务器层这些基础组件的监控。网关层面更注重的是流量的监控,所以业务团队除了一些基本业务指标监控之外,也会做一些业务细节的监控,比如可用率、性能、异常量、错误码等等。比如说某个点的单量突然跌了,需要尽快定位到具体是什么原因引起,所以业务侧的监控更多是能一眼就能聚焦到引起问题的某个点上,通过预案快速修复问题。
而且我们上线、发布新的业务,都是要有灰度的。比如上线一个业务之后,只是其中的一部分流量走新业务。此时,我们通过埋点监控,去对比新老业务,看用户的反应,分析其影响,然后再做决策。
InfoQ:刚才提到埋点,那么大促过程中移动端设置的埋点跟平时有没有不同?大促结束后会不会关闭某些埋点?
赵云霄:埋点的作用分两种,一种是用来收集业务数据的埋点,另一种是监测系统指标的埋点。大促之前,我们会针对不同促销会增加一些的收集业务数据的埋点。京东的业务非常复杂,跟单纯做平台其实是不一样的。市场有时会做一些新业务,这时就可能要根据业务再判断如何增加埋点。用来监测系统指标的这些埋点基本不会变。
埋点基本上都是可以去关闭的。埋点要么是通过现在的技术,通过APP内网去申报,要么就是写在磁盘日志上。这两种埋点对网卡和磁盘都会造成比较大的损耗,所以没有用的埋点,我们会想办法动态关闭。
InfoQ:京东做了一套立体的监控,又设置了很多埋点,那么肯定是可以监控到非正常用户的。具体是怎样筛选出非正常用户的?移动端在管控这些非正常用户方面做了哪些工作?怎样保证快速隔离非正常的用户?
陈保安:对于非正常用户,我们会对接到京东集团的风控系统。风控系统利用对用户的积累,对用户做了很细致的分类,可以根据用户的行为采用模型算法对其进行识别。例如,有的用户每天就只有刷单操作,没有搜索等行为;有的虽然模拟用户进行多步操作再下单,但是下单的频率比较频繁,一秒钟下单很多次;还有些用户下单的商品全是无货商品,也就是说在活动开始之前,脚本已经启动了,而这段时间商品是无货的。利用最简单的这些特征,就能分析出来这些用户是非正常用户。
同时,在安全方面客户端和服务端之间也有一些基本的接口调动时候的安全限制。比如说签名,我会给你分配到签名,你要拿到对应的签名才能去访问相应的服务,这里也会有几种策略下发给客户端去用。但是非正常用户为什么可以刷单,就是因为破解了个别签名。这也是为什么还需要后端不断地去对用户行为分析。
具体的隔离方式:针对非正常用户,在关键时刻我们会做非常严格的限制,否则会对系统和商品销量造成很大的冲击。例如,在618和双十一零点时,会对识别出的用户做特殊处理。表面上会给他们提供一些服务,但实际上会把他们引流到一个具体的集群中,性能、稳定化不做保障,如果他们挂掉了,我们也不负责,这样才可以对正常用户做到保护。而即使是引流,他们最终访问的流量还是会透传到各个基础服务,在特殊紧急情况下,也会把这些用户掐掉。这些不同级别的限流都已经经过了演习并报备,目的都是为了保证正常用户。
InfoQ:相当于把非正常用户加入了黑名单,那么这份黑名单是怎么得到的呢?
赵云霄:得到这份黑名单非常不容易。京东有非常多的数据,也希望能利用这些数据对用户提供更好的服务。京东有一个专门的团队,利用大数据分析,通过数据模型不断地调整、优化,再利用从前端到后端的多级防控,才从海量的数据中分析得出用户的画像。
无线团队也会做一些比较简单的用户分析,也会要求他们为我们提出安全点。大家始终在做这种配合,然后根据用户的不同级别,做一些反馈。比如,像刚才提到的,在特殊情况下掐掉的非正常用户,都是我们真正有把握的非常用户,而不是模棱两可的。正常用户去抢购商品是不会被加入黑名单的,这样才能真正包含用户的利益。
同时,我们队黑名单也会做出动态调整。因为不同业务的业务模型是不一样的,对用户的分类是有差别的。所以需要跟专门的团队去沟通,让他们根据业务模型分析非正常用户。实际上,非正常用户的占比也是非常小的,这也让我们非常欣慰。
陈保安:这模型建立固定好后,通过埋点实时地埋过去,就可以算出真正的非正常用户。在大促时,经常遇到有人临时去注册一批用户的情况,但是只要他开始刷单,我们很快就能够识别出来。
InfoQ:据我所知,无线端对整个购物流程都做了非常细致的预案,能不能具体地说一下细致到了什么程度?开启的方式是自动化吗?在什么样的情况下会启动预案?
陈保安:整个京东针对618做了上千种预案,而无线部门也做了几百种预案,这个力度是都非常非常细的。大的预案例如机房的切换,而小的预案也有很多。
比如,京东App上搜索现在70%搜索的结果都是个性化的,这样一来缓存命中率会降低,服务器的压力就会增大。如果CPU使用率达到了40%,那么我们会通过降级个性化服务来保证用户能够快速访问。再比如现在支付环节要依赖京东台账和订单中心,如果服务出问题,我要通过降级保障用户能正常支付。
开启的方式有自动化的,也有人工的。比如httpDNS服务出现问题,客户端会自动降级到普通的DNS服务解析,这个影响范围比较大,那么就不能等人工去切换,要使用自动化方式。
关于何时启动预案,虽然往年我们为了保证最基本的购物体验,我们在零点时会做一些处理降级。但今年晨总要求了两点,一是技术保障,最基本的要求,二是业务驱动指标,就是说不能随便降级,要保障业务。
所以,包括之前提到的个性化,以往在零点去做一些降级,但是今年不会去做降级。但是一切大前提就是保障基础购物流程的体验,关键时候系统自我的保护就会启用一些预案,比如说单品页下面的个性推荐,只要它达到基础性能的某个比例后,我们就会采取一些紧急措施来保证整体商品的展示。
赵云霄:事实上每年都会做很多预案,在大促前都会有一个严格的评审。细致到什么程度呢?比如后端依赖某一个具体的接口,针对每一个接口都要有一个预案,包括资源的依赖都会有原。我们是尽可能地去考虑可能出现的问题。
预案启动的方式是自动还是人工需要看情况。
系统压力过大,CPU达到了40%,有这样的具体标准,那么可以采用自动启动。在自动启动预案时,都会向相关人员发送通知。
大促期间,有些情况比较复杂,是多种原因造成的,这时候就需要优秀的技术人员去处理,那么此时就需要人工启动。相应级别的人会有判断和执行的权利,但是在事前和事后都要周知一下。预案的执行有流程,也有反馈,这我们预案执行的大原则。
有了之前提到的强大监控系统来提供一些判断依据,预案的执行效果还是比较好的。
事实上,预案有专门的分归类,不同模块的人会去管理自己的预案。在执行时也会遵循保证用户正常体验的大原则。
InfoQ:京东的无线端一步步发展至今,两位想必有很多感慨吧?
陈保安:对,我跟云霄就是从无线成立到现在,一步一步走过来的。在四五年前,无线只是试水,那时我们还叫手机移动端。上了一万单时,大家很开心,还专门庆祝了一番。现在,我们的访问人次和订单量在当时都是难以想象的,比如,过去一个月的日均活跃用户数已经接近4000万,技术团队由最初的两三个人发展到现在的过百人,有了比较完善的架构。
赵云霄:我们整个技术团队也是随着流量的不断增加而慢慢成长起来的。开始,我们会参照别人的技术,羡慕别人的技术。后来,我们有了很多问题要去解决,在这个过程中也积累了很多经验。现在,我们不需要再去参照别人了,而是要将自己的经验分享给大家。因为我们发现,很多人一路走来,面临的问题都是相似的,只是处于不同的阶段。
京东给了移动端快速成长的机会,让我们不断进步。我们也一直保持着对技术的旺盛求知。网上有一些技术贴,说京东的技术如何如何,我们没人去霹谣,因为谣言太多了。你可以说京东只是流量很大,但我会说京东的系统复杂度是最大的。我们经历了这么一个体系的成长,现在也有了一个足可以让我们自己去仰望的平台。