一、起因
除夕夜晚上9点多到家,打开电视看春晚。
听到主持人说打开百度摇红包的时候,心里一喜,立刻打开百度APP摇了几个红包,但部分红包需要下载其他APP才能领取。于是打开某应用商店,出我意料的,某应用商店竟然挂了,于是返回APP继续愉快的摇红包,最后一共中了几块钱。
第二天大年初一看到新闻说由于百度红包总流量达到了X亿,苹果华为小米等应用商店全因此挂掉。本着对技术的好奇,根据新闻里给出的公开数据,我粗略计算了一下,当时的计算结果是对服务器的平均访问次数大概在每秒1300万-1500万次,峰值可能在1亿次以上。
不久之后,怀着对技术大牛的敬意,拜读了《百度的春晚战事》(https://mp.weixin.qq.com/s/W9Nbq64v9doYPxcCLBsqNQ)这篇文章。文章中说对服务器访问峰值是5000万/秒,百度因此准备了10万台服务器(文章中没有说明这10万台服务器用于任务三的比例是多少,我暂且认为都是用于任务三的)。这很大的出乎了我的意料,出于技术人员的本能,我仔细思考了一下,觉得可以优化一番。
二、业务逻辑
1)登陆:这是必不可少的步骤,由于文章中没有具体技术细节的描述,所以该系统暂时不考虑优化;
2)摇奖:奖金分成小奖(高发无耦合个体事件)和大奖(偶发需要同步事件);
3)下载APP兑奖:下载的APP需要打开后通知后台这份奖品可以领取;
4)中奖结算:中奖并不是实时结算的,而是需要按照一定的间隔结算;
5)奖金剩余:本阶段剩余奖金数,实际过程中发现该数值的更新并不是特别实时;
6)大奖剩余:没中过大奖,所以并不知道是什么流程。
三、春晚摇奖服务架构设计
假设客户端链接一共有1亿。
用类似于Zookeeper服务器同步奖品数量,10万台服务器均匀的分担1亿链接,每台服务器承载1000个客户端长链接,每个客户端2秒摇奖一次,那么每台服务器每秒接受500条访问数据。
这个结构基本符合春晚摇奖的承载和表现。
四、优化
前提说完,直接说优化逻辑:
1)登陆过后,由客户端账号名等唯一ID用简单与或移位操作产生的hashkey,并保存在服务器端。
2)我们可以根据:“用户获奖最多不超过100次”,“不应该有用户连续获奖”,“单个用户不应该获得两次大奖”等等业务规则来提前制作一个随机数表,用hashkey作为随机数表的offset种子。此随机数表用于产生客户端获奖步长、服务器端对于客户端获奖校验等。
也就是说,在账号登陆之时,客户端都在第几次摇奖获得了什么奖,都已经约定好了。唯一的问题是:我们不知道客户将要摇多少次(但是我们知道最多只能摇多少次)。
3)客户端摇奖是否中奖/中什么奖,自己计算并且显示就可以了。
初期,客户端在未产生大奖的时候,以获奖步长往服务器端发消息同步摇奖次数这个数据,服务器返回奖池剩余金额/是否可以继续获奖就可以了。同步完成后关闭链接;
后期,当奖金池金额较少的时候,服务器根据奖池余额逐步中止客户端获奖;
这期间客户端在产生大奖的时候,需要先向服务器同步获得大奖请求,服务器检查大奖余量,如果有让客户端中大奖并记录,如果没有则返回失败。
这个逻辑符合百度摇奖在每个阶段初期中奖率较高,后期中奖率降低直至没有的实际情况。
如果客户端断网,那么甚至可以在中奖结算阶段再同步就可以了。
4)下载APP兑奖由于是小频率事件,发送消息次数很少,按照目前架构逻辑即可。
5)承载计算(假设客户端链接一共有1亿)
a)1亿/200台服务器,每台服务器需要承载5万人;
b)由于采用以上逻辑之后,每个客户端同步数据量极小,同步的频率可以极低,我们按照每100秒同步一次计算,那么每秒需要同步数据的客户端是500个,同步数据是500条。
五、问题
上述业务逻辑设计,完全满足百度春晚摇奖业务要求,并且不会产生作弊,奖金总额/大奖超标,客户端断网摇奖失效等问题,并且用户感受跟目前的业务设计相同。
可能会产生的问题有:
1)所有用户的全部小奖总额可能会有偏差(我估计百度目前架构也有这个问题)。
2)由于服务器数量少,中奖结算会比目前架构略慢,但经过技术优化后不会慢太多。
六、后续
上述业务逻辑优化完成后,还可以进行技术优化,不知道会不会有人想看《浅谈如何从业务逻辑角度将百度春晚红包服务器从10万台优化到200台后,再从技术角度优化到20台》这样的文章,如果想看的人多,我会找时间写一下如何从技术角度尽全力压榨服务器能力的文章。最后希望大家提出问题,一起讨论。