基本任务
中秋节的前一天,SAE突然接到一个电话,有这么一个客户,他们专门给银行、基金公司提供营销服务,这回他们服务的是一个“金主”,准备做一个在中秋节当天通过微信发送现金红包的活动,活动本身就是一个HTML5页面,里面的逻辑不难,也就不到1000行代码,大体是:
if ( 该用户没有参与过活动 & 余额有钱)
跳转到游戏页面
begin game
生成中奖信息
扣款
调用微信红包API
end game
else
提示“已经参与过了”,并显示中奖信息
那么问题来了
就这么一个简单的业务,却困扰了这个客户长达两年,连续两年的中秋抽奖都没有成功过,每次都以宕机=》刷不出页面结束,作为营销公司,他们也受到了他们的客户的质疑。那么前两年的抽奖活动怎么做的呢?
第一年:用自己的服务器,12核/16G内存一台,里面跑着LAMP(Apache+MySQL+PHP),结果CPU跑满,不得不停重启
第二年:用了某云的云服务器,16核心/32G内存,IO优化实例一个,里面跑着LAMP(同上),结果负载巨高,响应巨慢
很不幸,两次活动都不成功,所以客户找到了SAE。。。
分析问题
得到需求后,因为离最终上线只有一天,SAE立即派出技术团队到了位于北京西直门的这家上市营销公司了解情况,经过沟通,我们来分析一下这个案例:
- 1,此次活动的领域基本集中在朋友圈传播,目的是增加粉丝,并不是转发量,所以没有动用大号转发,加上抽的是实际现金(他们的客户要求必须现金不玩假抽奖劵,果然金主啊^_^),很快会抽完,持续时间不长,所以总体量不大
- 2,钱是通过微信接口预充进去的,最麻烦的支付扣款是调用微信接口,用户看到的就是一个标准的红包页面,所以免去了事务支付的重逻辑
- 3,访问的终端用户是银行的全国用户,HTML5游戏里面含大量静态元素,原程序没有使用CDN做资源加速
- 4,原有逻辑大量依赖MySQL数据库,且表结构存在不合理,也没有适当的使用cache,更没有使用读写分离,导致瞬间数据库压力过大
- 5,业务上没有峰值预案,也没有降级逻辑
- 6,只使用云主机,不具备自动扩容能力,客户也没有scale out的实施经验
解决
考虑到这些原因,同时考虑到离实际活动发布还有不到12个小时,不可能对原有逻辑进行大改,所以只能放弃5(降级逻辑)
那么,我们所做的工作有:
1,将业务放到SAE上,因为SAE实现了基于HTTP Request的container,可以随着请求的增多而自动扩容,整个过程用户无感知也无需关心,换句话说从1000PV到10亿PV用户无需做任何变动即可完成,这样首先解决Apache+PHP的运行负载问题
2,单单完成1是不够的,因为涉及到数据库还是单点,所以我们协助用户修改数据操作为读写分离,根据这个业务场景,用户的钱可以有一些误差,不是严格要求发放XX万元整(因为剩余的钱微信会退回商家),于是,诸如余额是否有钱的操作不必严格使用tranaction保证,可以直接从从库判断
3,增加cache层,首先设置HTTP过期header和启用CDN,从多个层面增加cache效果,在SAE上启用CDN非常简单,参考http://www.sinacloud.com/doc/sae/php/cdn.html,只要将资源地址改成CDN域名即可;使用memcache服务作为数据cache层,所有数据均从cache读取,对于需要事务的数据,使用memcache::add操作间接实现,另外说一句,SAE上memcache不像目前的所谓的“微服务”,需要用户自己创建,而是SAE官方自带的“池化”服务,每个用户自动可以使用多达4T的内存cache。
4,变数据库批量并发写为有限并发异步写,创建了一个TaskQueue,将所有的数据库写操作放入并发度为16的Queue,通过该Queue异步update数据库。同时,SAE为企业用户提供了最高50000 IOPS的DB实例。
5,因为时间关系,未完成的逻辑有:变简单写操作从MySQL转到KVDB(NoSQL数据库);增加业务降级开关,紧急情况下操作HTML5客户端随机数,控制到达服务端的用户数量
在完成这些修改后,应用户的强烈要求,SAE还将这家营销公司的账号企业等级临时从高级型调整成最高等级(合作伙伴级)一天,来准备应对中秋的秒杀活动。至此,我们已经坚信这次秒杀可以支持瞬间10万并发,这个指标已经超过用户设计的十倍,当然,客户还是将信将疑,那么结果呢?
结果
客户的活动准时在2015年9月27日上午10点整开始:
如上图所述,中秋枪红包活动发布后,最高时达到了7万次请求/秒,在红包空了以后,请求迅速下降。同时,从用户日志看,没有错误日志产生,也没有502、504等超时现象,根据客户反馈,该次活动非常成功,他们的客户的现金红包大约在30秒内被抢光。之后,我们查阅了当时memcache集群和MySQL集群的状态,所有服务参数显示正常,证明这次秒杀行为从技术上完全满足。
总结
其实,从互联网的业务看,这次活动也不算太大,毕竟客户追求的并不是转发量而是粉丝数,另外他们的客户的红包金额也不是巨大,所以这次业务的峰值量离我们的预估还有一定距离,但从这次秒杀行为还有一些经验需要总结的:
1,不要迷信云服务,IaaS几乎不能帮用户解决完全自动的扩容问题,SAE也只能帮用户解决无状态的服务扩容,但像强业务逻辑的数据扩容还是有赖于用户自己解决,比如如果用户还是把所有的库、表操作放到一个单点执行,即使放到SAE上,也还是会出现瓶颈。
2,充分利用cache,cache不仅仅是利用redis或者memcache,而应该是从客户端、到代理层、到Runtime层、到数据库的各级cache,同时利用cache的过期时间,合理控制cache的实效性弊端
3,变一切同步操作为异步操作,尤其是写数据库的重操作,可以使用诸如TaskQueue服务来将逻辑异步化,让整个用户体验不存在阻塞逻辑
最后,还要在业务逻辑上实现可降级可控制,这点虽然因为时间关系未能在实际代码上有所体现,但是在实际大型业务确是最重要的。
当然,这里讲的秒杀还不包括支付系统的,从这点来说,这个案例要比淘宝、天猫等简单成千上万倍,我们也欢迎对秒杀技术有兴趣的小伙伴一起参与讨论,一起提高。