天猫双 11 互动性能优化

lilmm038 7年前
   <p>2016双11晚会狂欢夜当晚,千万粉丝坐在家里拿起手机就可以“同步”参与和舞台明星的“双向互动”,善于思考的你一定会去想,对于技术人员来说,如何扛住这海量的用户请求,准确公平地让每个粉丝贡献出力量又得到回报,同时,让一切过程分秒不差的出现在电视和手机里,是一个大大的难题...</p>    <p>今天的分享将会为你揭秘:</p>    <ol>     <li> <p>如何扛住4小时不间断的点赞请求?</p> </li>     <li> <p>同时,如何秒级实时的统计出PV、UV,和用户点赞的排行?</p> </li>     <li> <p>如何实现,让统计数据,同步出现在电视画面和手机画面?</p> </li>     <li> <p>新职业“互联网导播”是做什么的?</p> </li>    </ol>    <p><img src="https://simg.open-open.com/show/74e038a448124ffc4f4ce504ba068ded.jpg"></p>    <p>两个案例,一个是听起来很简单的点赞功能;另外一个是在电视信号延迟的情况下,怎么做到电视和手机“同步切换”的。最后,我们的“互联网导播”是怎么工作的?如何保障各种互动的平滑进行的。</p>    <p><img src="https://simg.open-open.com/show/6d6bafc1d13f0f6b93d09a29bdc3a8df.jpg"></p>    <p>这几张图是晚会当天手机、电视屏幕的一些场景截图,为了方便大家理解后面的内容,请收好。</p>    <p>图一是晚会的招牌互动玩法: 红黑大PK ,这个玩法去年第一届晚会就有,今年和去年逻辑大体相同:舞台上的明星分成红黑两队进行游戏PK,游戏开始之前,手机可以在用户的这个页面,选择押宝其中的一队,等舞台上分出胜负之后,押中的用户就可以摇一摇开宝箱,有机会获得1元商品的购买特权。图中看到的这场PK,我们在短短几秒内送出了10w份面膜套装。</p>    <p>红黑PK今年和去年不一样的地方在于,今年我们做了玩法升级,支持了 “双向互动” 。什么是双向互动?图中可以看到每张手机的截图,右下方都有点赞的按钮。第一张图里,在我选择了黑队之后,赞也变成了黑色氛围,点击它就会给黑队加油助力。舞台上,主持人可以实时看到每个队伍的点赞情况,电视机前的观众也可以看到一样的数字。就如第二张图的上部,王祖蓝右边就是红黑两队点赞的比例。获得用户点赞数量多的队伍,会获得一些游戏规则上的倾斜,比如:获得一些道具,减少一些时间等,增加获胜的概率。这样用户的参与感更强,用户不止是被动等待红黑PK的结果,还可以通过努力点赞,影响到最终的胜负。让自己喜欢的队伍获胜,同时也为自己赢得奖品!</p>    <p>红黑PK的升级版只是今年"双向互动"玩法的其中一种,其他玩法还有:AB剧:我们提供A剧情和B剧情,直接由用户决定剧情的发展路线。跨屏抢星衣:点赞满足条件后,明星会脱下身上的衣服,丢向屏幕,送给参与互动的观众。图为女神林志玲丢出他的Burberry风衣。</p>    <p>图三是一个下一节转场时的明星预告和红包入口。手机页面,什么时候由互动环节页面切换到这个画面、这个画面什么时候结束掉,这个完全是和电视同步的。当主持人口播开始押宝,或抢红包时,用户低头一看手机,按钮就在那里,就可以无缝的参与进来。这个是由我们现场的“互联网导播”实时操控。技术上如何做到这点的,我们后面也会讲。</p>    <p>图四,是在天猫APP中独有的舔屏版晚会直播。除了内容非常独特可以舔屏之外,也是让身边没有电视的用户,能打开手猫观看直播,同样无缝的参与互动。</p>    <p>再来看另一个“双向互动”玩法 “点赞得答谢” ,比如这场SNH48团体的歌舞表演中,观众点赞后,我们后台会实时统计出一个用户点赞数的排名。点赞多的用户,他的淘宝头像和昵称,就有机会展示在电视屏幕,并获得偶像的亲口答谢。</p>    <p>这种双向互动的玩法,结合粉丝经济,产生出了巨大的能量。但技术如何实现并支撑,也是一个大难题。有的同学可能会说,点赞有什么难的,一个AtomicInt就能解决...别急,继续往后看。</p>    <p><img src="https://simg.open-open.com/show/1fdf3903330a251ed257ca7b2f175210.jpg"></p>    <p>关于点赞,我们的评估是 千亿级 。千亿什么概念?全世界人口是70多亿,要达到这个数字,需要全世界每人点赞14次。怎么承接如此集中而又巨大的点赞量,并实时给出排行榜。</p>    <p><img src="https://simg.open-open.com/show/28bd2ca4b4d979650840668350b50f28.jpg"></p>    <p><img src="https://simg.open-open.com/show/8d21f92876887e84a02c41676b0388e9.jpg"></p>    <p>上图是一个最普通的点赞链路设计,首先它是可行的,互动很多小型的类似点赞活动就是用这套方案实现的。用户手机来点赞,请求通过负载均衡策略到服务端集群的其中一台服务器,再到可持久化的集群,这个持久化集群可以是db、也可以是缓存,但我们大多是用缓存。图中可以看到我们的几个需求,我们要知道 单一节目的点赞PV/UV、用户在某一节目的点赞PV、某一节目的用户点赞数排行榜 。纯点赞,可能一个AtomicInt、AtomicLong就能搞定,但是现在我们多出来的这个数据需求,就不那么简单了。</p>    <p>先来看看这个链路的问题。首先,我们评估的1000亿点赞数,平均到晚会的4个小时,算出来每秒需要承接700w的点赞。平均700w的QPS,目前很少有集群能撑到吧?</p>    <p>第二,单一节目的点赞PV,这个缓存的key,在同一时间,只会有一个存在,所有的QPS都是到这一个key上的。所以这里肯定也有热点key问题。</p>    <p>然后,针对UV,传统的做法是找个持久化的地方存一下用户来玩过的标识。每次点赞的时候,再查一下,查不到,则UV加一。那么这又多了至少一次缓存的读写,QPS那么要double了。</p>    <p>最后,排行榜这个东西,利用redis的zscore、zrank,是可以轻易完成的。但是在晚会这个量级,这么大QPS的前提下,必然也是存在瓶颈的。</p>    <p>我们怎么解决的呢?</p>    <p>先是我们简单粗暴的第一招。客户端本地离线点赞,比如x秒提交一次,或者数字到100提交一次 ,这个办法有效的降低了qps。(但其实这个离线的阈值并不能太大,因为用户可能在操作完就离开了客户端,最后一次都是丢失的。)这里用x=10举例,这样接口qps就直接降到了70w。</p>    <p><img src="https://simg.open-open.com/show/c21118812774fac0756c98581784819d.jpg"></p>    <p>看到评估数字从700万降到了70万,是不是大家也都松了一口气?</p>    <p>就这样,前面的第一个服务端QPS的问题就解决了。相应的, K2-用户点赞PV ,因为和用户相关,没有热点key问题,所以也是ok的(单用户点赞QPS理论不会达到集群限制)。</p>    <p>接下来,看看热点key的问题。</p>    <p>因为是计数的PV服务,服务端集群的各个服务器直接无须依赖持久化的旧值。所以我们可以在服务端做一个离线。比如,服务端Y秒才上报持久话一次,这样极限情况,缓存的QPS就等于机器数,这样就解决了热点问题。而且,通过内存先做PV的统计,这是纯内存的逻辑了,不会成为性能瓶颈。</p>    <p>值得一说的是,这两个地方的离线,都需要做好并发控制。客户端的离线,要支持节目的瞬时切换不丢数据。服务端的离线,不能让RT相对高的上报请求,阻塞RT低的内存技术请求。这里关于数据结构有些Tips:客户端离线用一个map结构,key是节目id,值是计数器。计数时做incr,上报异步做,成功后desc。服务端离线稍复杂一些,我们构造了一个数据结构,叫做MIT(memory increase tool),如图是一个包含时间戳long和计数器atomicLong的数据结构,然后再封装了一些每隔x秒自动持久化,以及并发处理。这个并发处理要求在持久化时,不能阻塞atomicLong的计数,也不能出错。</p>    <p><img src="https://simg.open-open.com/show/d1355198c5c0bd238a170b9da420c0cb.jpg"></p>    <p>再来说UV。</p>    <p>其实完全可以基于incr的初始值,判断有没有来过,省去一次uid去重的读写缓存。是不是?</p>    <p>这样依赖,UV的QPS绝对会远远小于70w,甚至忽略不计。</p>    <p><img src="https://simg.open-open.com/show/53d6366768d76643881ebdfabe4afd14.jpg"></p>    <p>前面节目PV、UV、用户PV的问题,都想到办法解决了,就剩下点赞排行的问题了。</p>    <p><img src="https://simg.open-open.com/show/d58d9871d4b8b902ad877559ada9c1f7.jpg"></p>    <p>排行这里,我们仿照选举机制,设计了一种先单机排序的方案。比如:100个城市同时选举总统,用户可以去不同城市投票,把每个城市选出的候选人,合并一下,必然能找出票数最多的。</p>    <p>其实可以发现,这和前面的MIT缓存机制很像,没错,这里的单机排序,也是可以定时持久化的,比如1秒1次,然后获取排行榜时,只需要去所有机器上,拿到列表,然后合并就可以了。在实际场景, K2-用户点赞PV 这个key incr之后返回的数据,其实已经是用户实时最新的点赞数据了,其实可以直接参与排行。当然,先和排行最后一名相比较,比最后一名多,再参与排行,这是一个小优化。</p>    <p>然后,这个数据结构,也是需要有一些要求:</p>    <ul>     <li> <p>线程安全</p> </li>     <li> <p>自动排序</p> </li>     <li> <p>自动逐出</p> </li>     <li> <p>定时持久化时不阻塞</p> </li>     <li> <p>高并发写入也有高性能</p> </li>    </ul>    <p><img src="https://simg.open-open.com/show/7c7c2a58dcafdc5e4dd8e0106f2dbfed.jpg"></p>    <p>这里总结一下:</p>    <ul>     <li> <p>客户端最后x秒有损,但服务端y秒缓存可以无损,加个定时钟补偿推动,incr 0就行了。</p> </li>     <li> <p>缓存计数器的一般实现是int,在1000亿目标下,单节目有溢出风险,可以尝试21亿进制。</p> </li>     <li> <p>非热点的用户PV缓存,也要做好限流。我们认为这个场景不会超,若超则是作弊用户,但服务端也要自我保护限流。</p> </li>     <li> <p>内存排序的建议实现方式是:基于跳表(skipList)</p> </li>    </ul>    <p><img src="https://simg.open-open.com/show/86d96056a91d9d7cd302edde3da5c0e9.jpg"></p>    <p>今年玩法比较复杂,为了便于理解,先说说去年的“同步”这件事。</p>    <p>图中是红黑PK的几个时间点,可以看出舞台画面,呈现到电视机,都会有60s的延迟。我们的解决办法如图:</p>    <ol>     <li> <p>后台工作人员,在主持人发出指令时,同时操作数据;</p> </li>     <li> <p>在60s内,这个数据的变化,手机被同步到了;</p> </li>     <li> <p>手机知道了60s后,电视机画面会发生什么,于是设置定时器,到点了自动跳出相应内容;</p> </li>    </ol>    <p>这样就实现了,手机内容和电视画面保持一致。这里,较为困难的就是 2. 60s内让手机知道 ,为了保证这个能尽量100%覆盖,我们用的方式是轮询,40s轮询1次,于是60s内会有2次,经过去年的实际验证,这种方式是简单、靠谱、稳定的。</p>    <p><img src="https://simg.open-open.com/show/d6818f028fc0e35f5ce555f3c53ba449.jpg"></p>    <p>然后我们来看今年的问题,这也是由“双向同步”玩法而引入的。前面说过,用户选完红黑,可以给选中的队伍点赞,增加支持队伍的获胜概率,这里就需要一个“点赞结束统计” 的时间点。</p>    <p>在这个时间点之前,电视里还有一个L屏,可以实时的看到点赞的进度。那么问题来了,这个点赞的数据,怎么来呢?</p>    <p>我们可以分析一下,最下边,绿色条是用户可以点赞的时间段。舞台说点赞结束的时候,就需要拿到一个数字,但用户实际结束点赞,需要1分钟之后。怎么让舞台现场预知到1分钟之后的点赞数呢??</p>    <p>答案是没法知道...科幻世界里才有这技能...</p>    <p>所以我们的统计只能在time6这个点,就截止掉。然后time6鱼time6'之间的点赞数据,我们依然会统计,但是就不能作为双向互动的依据了。</p>    <p>你以为问题解决了? 其实才刚刚开始...</p>    <p>现场在time6获取到的点赞结果,会在time6’出现在观众的电视画面,但手机怎么获取到这个值?这时候后台点赞计数器,其实已经是1分钟之后的数字了?举个例子,现场在time6这个点,赞数由100变为101,电视画面L屏是合成进去的,在time6'的时候,也是刚好100变为101,这个没有问题;但手机要完全同步,它需要在time6'的时候,显示的是time6的是点赞数,这个数字从哪里来?计数器里的已经差了1分钟了。甚至这个问题并不只是一个time6实际点存在,整个点赞期间,都存在这个问题。</p>    <p><img src="https://simg.open-open.com/show/30c2fb703c43d5c8e0c621d41fd8dcef.jpg"></p>    <p>怎么解决?我们发明了一种 时光隧道 机制,点赞计数的时候,定时钟按照一定的时间片,缓存起来一份快照数据。手机端请求时,经过一些时间的计算、hash到时间片,就可以取到60秒之前的数据了。这样就解决了这个问题。</p>    <p>整个时间延迟的解决过程,我们偶尔需要向前感知60s,一会需要向后回溯60s,分清楚过去、现在、和未来,保持正确性、体验一致性,这就是我们的玩转时间。</p>    <p><img src="https://simg.open-open.com/show/3e82b49aee7bd7b79d92e160c5a5ea07.jpg"></p>    <p>在时间的处理上,还有一些性能的热区问题。比如下面标红部分,押宝通道开启、宝箱开启时,押注接口和抽奖接口,都会迎来史上最高峰。一方面我们要保证这些接口性能容量已经优化到了极致,一方面,还要让其他接口,不要在这里竞争资源。比如前面说道的,40s轮询一次,但这个峰值前后的40秒不会有事件变化,其实这里就可以跳过至少1次轮询。还有中间的进度条峰值,就干脆和轮询结合在一起,只是变为5s查一下,这样QPS会是之前的8倍,但是因为可以错峰,这时候并没有押注或抽奖,所以抗住不是问题。</p>    <p><img src="https://simg.open-open.com/show/9f64c952de83c49a54c274ecc992d806.jpg"></p>    <p>协议架构。首先是刚刚说的轮询接口、押注接口、抽奖接口。通过淘系的长链接sdk,ssl的spdy协议,访问到了后台互动服务。为了性能极致,像刚刚的轮询接口,就是一次内存读;押注接口,就是一次缓存写;还有前面重点说的点赞接口,平均也就是1次缓存写。这里的缓存是专用的高性能缓存,阿里系的tair中间件。上面的通用缓存,是给抽奖服务使用的,抽奖服务不用硬抗大流量,合理限流就行。</p>    <p>这里需要重点说明的是下行链路,“开启押宝通道”这类事件的变化,是怎么通知到手机的。</p>    <p>可以看绿色箭头,导播在控制台点击“开启押宝通道”按钮后,会写入一次“配置开关中间件”,这个中间件就是昨天下午第一场的讲师叔同团队开发维护的,非常稳定好用。配置开关保存成功之后,会刷入到时间表的内存,这样轮询接口就能读到数据了。</p>    <p>今年,我们还使用了另外一条链路,是基于spdy协议实现的反向推送,在现有长链接基础之上,封装了一个topic主题的概念,反向推送时,只需要向这个主题下的所有在线用户做推送就可以了。</p>    <p>为什么会有两种方式?手机是移动设备,网络稳定性较差。长链接推送通道也存在失联可能性,我们设计了一个消息失联的回调机制,当一台手机失联后,会自动切换到轮询模式,增强健壮性,让更多的用户可以继续正常参与到晚会的互动中来。</p>    <p><img src="https://simg.open-open.com/show/5ad6ae7f39f6dba0be4a141a3cdd0b3f.jpg"></p>    <p>再总结一下。如图。</p>    <p><img src="https://simg.open-open.com/show/0226ac1e150fc98981d9c9593d216d4f.jpg"></p>    <p>继续下一个话题前,先说一个前面提到的双向互动“跨屏抢星衣”的流程,原理也是前面说的时间同步机制,不过结合了AR玩法和双屏酷炫动画衔接,给用户一种穿越、跨屏的震撼感觉,成为了晚会的一个爆点。</p>    <p>这里其实要求更多的团队和系统,做到协调一致的,怎么保证,这是就是我们下面要说的“互联网导播”。</p>    <p><img src="https://simg.open-open.com/show/0aeaadf3925f700c653f1cf6be968bdb.jpg"></p>    <p>“互联网导播”现在并没有一个公共的解释。完全是双11天猫晚会首创的工种。</p>    <p><img src="https://simg.open-open.com/show/ede03e229ed9a1c024757f35c04923af.jpg"></p>    <p>再介绍“互联网导播”之前,先说一下,传统的导播,也就是“电视导播”。</p>    <p>电视导播一般在直播车内,盯着很多屏幕,每一个屏幕是一路摄像信号。然后他操作一个硬件“控制台”,通过一个个按钮,讲最合适的画面,输出到一路最终的信号里,然后通过卫星,到了千家万户的电视机里。</p>    <p><img src="https://simg.open-open.com/show/cbae7b38503a2c9a51e52f8f0a1d6bd7.jpg"></p>    <p>而“互联网导播”有些类似,他也有“控制台”,不过这个控制台是高度定制化的Web页面。他盯的不是屏幕信号,而是现场画面以及留意主持人口播Q点。然后,他切换的是手机里的互动内容,并且解决了延迟的问题,做到了同步电视而切换。</p>    <p>并且“互联网导播”会比电视导播更加危险,电视导播切错了一个画面,几秒内切回来不一定有人发现。而“互联网导播”切错了一个内容,几秒内可能就是成百上千万的资损。所以,互联网导播的控制台,我们也称之为“核按钮”。</p>    <p><img src="https://simg.open-open.com/show/ce16f33a3c61d625ee226985dcc9bf16.jpg"></p>    <p><img src="https://simg.open-open.com/show/d0cbf23696a42a950fbd13534a2e3737.jpg"></p>    <p>最后,总结一下这两年做“互联网导播”的心得。</p>    <ol>     <li> <p>“控制台”的依赖,也要简单到极致。比如,写入就只写入一个中间件就行。</p> </li>     <li> <p>现场可视化。包括两部分:控制台操作结果可视化、现场用户参与情况可视化。</p> </li>     <li> <p>“控制台”按钮合理校验。比如:开启押注一定要关闭押注之前的校验。</p> </li>     <li> <p>“控制台”按钮固化,单一功能。但灵活是说,遇到万一,也有其他按钮,可以迅速纠正。</p> </li>     <li> <p>不同操作者,做好隔离,防止互相影响。</p> </li>    </ol>    <p> </p>    <p>来自:http://mp.weixin.qq.com/s/jy9kGn-l2_PTgoaHkxGS4g</p>    <p> </p>