回复内容:
1. 秒杀活动的技术挑战
假设某网站秒杀活动只推出一件商品,预计会吸引1万人参加活动,也就说最大并发请求数是10000,秒杀系统需要面对的技术挑战有:
对现有网站业务造成冲击秒杀活动只是网站营销的一个附加活动,这个活动具有时间短,并发访问量大的特点,如果和网站原有应用部署在一起,必然会对现有业务造成冲击,稍有不慎可能导致整个网站瘫痪。
高并发下的应用、数据库负载用户在秒杀开始前,通过不停的刷新浏览器页面以保证不会错过秒杀,这些请求如果按照一般的网站应用架构,访问应用服务器、连接数据库,会对应用服务器、数据库服务器造成极大的负载压力。
突然增加的网络及服务器带宽假设商品页面大小200K(主要是商品图片大小),那么需要的网络和服务器带宽是2G(200K×10,000),这些网络带宽是因为秒杀活动新增的,超过网站平时使用的带宽。
直接下单秒杀的游戏规则是到了秒杀时间才能开始对商品下单购买,在此时间点之前,只能浏览商品信息,不能下单。而下单页面也是一个普通的URL,如果得到这个URL,不用等到秒杀开始就可以下单了。
2. 秒杀系统的应对策略
为了应对上述挑战,秒杀系统的策略有:
秒杀系统独立部署为了避免因为秒杀活动的高并发访问而拖垮整个网站,使整个网站不必面对蜂拥而来的用户访问,将秒杀系统独立部署,如果需要,还可以使用独立的域名,以和网站完全隔离,即使秒杀系统崩溃了,也不会对网站造成任何影响。
秒杀商品页面静态化秒杀商品页面重新设计,不使用网站原来的商品详情页面,页面内容静态化:商品描述,商品参数,成交记录,用户评价全部写入一个静态页面,用户请求不需要经过应用服务器的业务逻辑处理,也不需要访问数据库。所以秒杀商品服务不需要部署动态的Web服务器、数据库服务器。
租借秒杀活动网络带宽对于因为秒杀新增的网络带宽,必须和运营商重新购买或者租借。为了减轻网站服务器的压力,需要将秒杀商品页面缓存在CDN,同样需要和CDN服务商临时租借新增的出口带宽。
动态生成随机下单页面URL为了避免用户直接访问下单页面URL,需要将该URL动态化,即使秒杀系统的开发者也无法在秒杀开始前访问下单页面的URL。办法是在下单页面URL加入由服务器端生成的随机数作为参数,在秒杀开始的时候才能得到。
3. 秒杀系统架构设计
--摘自《大型网站技术架构》
http://t.cn/z8N27YQ
让我设计的话,可能会用队列,时间一到就开始往队列里放,取队列是单线程,队列设置长度限制,上限就是商品数,如果消费线程发现商品已经卖完了,就通知前端停止接收新请求。
本人并没有参与过淘宝的秒杀系统设计。以下内容都是我设想的,而且只谈概念,这玩意谈概念就行了,具体实现随便找点就可以有很多种。
秒杀的核心问题在于全局和原子性操作,这基本上是反潮流的,现在的潮流不管是数据库系统或者是消息系统都是分布式的,比如Greenplum或者Kafka,再有Redis
这些系统有个巨大问题就是在分布式的场景下做到时序是很困难,或者说代价很大,或者说,没啥必要。
但秒杀系统却不是如此,这种场景需要时序。单点设计也许是必然的。
为此,你首先需要知道的并不是什么大规模网站,超高PV网站所需要了解的那些HTTP优化,数据库优化之类的话题,你需要知道的是短板在哪里,这个场景下,短板是这个可能存在单点。
首先,你需要知道你的极限是什么,这里设计两点:
- 极限峰值
- 完整持久化,备份所需要的代价
第一个问题,你可以设计一个程序尝试一下,往一个有网络传输的前提下往一个Hash里面不断加入纪录并且拒绝并行化能承担的最大TPS, 个人估计,应该在几万这样的当量上。
这里是不包含磁盘写入或备份传输的,因为这些你可以事后做,而不必要在秒杀当时做。这里有个矛盾,如果你的这个单点是持续高负载,导致你持久化无法持续完成,那你只能拿一条写一条。为此,你会付出很多代价。同时,你也存在资源浪费,因为你的CPU可能空闲,而磁盘非常忙。这也是dump存在的意义。
第二个问题上面已经解释一些了,但,你可能付出更多的代价,因为持久化你也可能不够满意,你可能需要寄送日志系统,寄送Hadoop存储,写数据库等等,为此,可能非常慢
在了解以上以后,你可以尝试看看负载是否能满足你的要求,比如你有几百个库存,那这样可能已经满足你了,1秒内就以非常小的并发就秒完了,之后的只要拒绝就行了
如果是几万的,要在一秒内,就比较狗血了,为此你可能为此在进入这个单点之前就要设置拒绝率,也就是某些人可能是在这个时序之前就秒杀到了,但你却要拒绝他。但用户很难发现,因为这当中涉及的系统非常多,有个几百毫秒的延时也很正常。
如果是几百万库存的(我不知道是否存在这样的场景),那你必须分布式来解决,找很多个单点以一种哈希形式来分布。为此,你可能存在一个单点没秒完,另外一个早就结束的哈希不均匀情况,这种场景非常常见,原因是你无法预测用户,而哈希方法是事先决定的。
这就凭经验了,我想做过很多次以后,应该能找到一个相对均匀的方法来分布你的秒杀需求。
本人没有接触过taobao秒杀系统的开发,所以是从不同角度来回答这个问题,仅作参考。
这类问题最开始应该先定好量级,不同量级的系统设计是完全不同的。
拿taobao举例,他们的秒杀系统肯定是世界独一无二的,在双十一零点,几亿用户开始刷新页面和App,对于Web服务和API服务的压力可想而知。
我将秒杀的预期降低,降低到我遇见过的量级,比如,一分钟内100万用户开始秒杀,这时系统如何处理。
我们再来看业务,秒杀业务特点是什么?我觉得有以下几点:
1,这个是用户需要购买/下单的,所以,如果我获得了资格,一定是有货物,我是可以支付的。相反,如果我看到了自己没拍到,也没所谓,因为抢不到很正常么。
2,用户一定是在特定时间点附近疯狂刷新的。
3,峰值数据流量巨大,这就是人肉DDOS攻击(肯定也有机器DDOS攻击的元素在里面)
对于这几类业务特点,逐一分析:
1.1,一百万用户,可能会购买上千万件物品(产生千万级的交易)。当用户取得资格后,服务器需要去处理这块交易。这里的行为时间点分布已经可以近似于正态,因为获取资格后,支付之类的行为会规定在一段时间内,比如15分钟内付款,或者当天付款。这种业务量一定是分布式交易系统才可以支撑,其中分布式消息队列、水平分割、多层负载均衡和多层缓存是一定会有的。至于技术选型、各家有各家的方法,这里不做过多的讨论,因为到这一层,从交易数量和频率上来看是正常水品中的了。
1.2,对于用户获取购买资格这块业务,就需要单独拆分出来,因为即使是一百万用户,在同一时间同时抢千万件商品,产生的请求可能是几亿的量级,考虑到这些请求可能出现在几秒钟内,几乎没有任何动态系统能够支撑。即使我先做了3/4层负载均衡,再去dns轮训,再去用一千台nginx分流到业务服务器,每个业务群组有100台服务器,每台服务器要处理的并发数量也是在1000transaction/second以上。这只是我yy出来的结果,前几年貌似听过fb/google之类的主要业务支撑服务器也就是在2k~5k台之间,至于这种1000x100=10w太服务器的量级,估计也没有负载均衡设备来支撑。So, 这里尽量降低动态数据对业务的影响,比如我们将商品抢购结果生成token队列,拿到中签token的用户才有资格去购买,这些token全部是静态数据,按队列形式获取。不同地理位置,安排不同的队列,提前分配好量,最终请求都不要落入交易的业务系统中。
2,对于用户疯狂刷新的行为,这里业务的量级是前面获取资格业务的至少10倍,也就是会产生几十亿次请求。两点应对策略:每次http请求url都不是相同的,也是token的机制,连接不能反复使用,这样防止了人肉/机器ddos的可能性。二是静态资源cdn,这样节约了主营业务的带宽。
3,对于流量问题,第二点中说的cdn外,前端js脚本以及app端的逻辑尽量能够引流。比如我手机不停刷刷刷,app在时间到达之前,或者http协议缓存过期前都返回本地缓存即可,cdn的流量都不需要。
总的来说:
app/html->cdn/各层负载均衡->业务拆分->数据拆分+异步处理/修复
来解决特定的业务需求。对于秒杀来说,业务拆分很重要,对于不可能完成的并发要求,讨巧的去静态化了而已。在我的认知里,支撑百万用户量级的解决方案就是这样的。对于taobao这类高3~4个数量级的业务需求,除了优化每个环节的服务能力,不同的业务解决方案也是必须的