【秒杀】一、系统设计要点,从卖病鹅说起

4,266 阅读12分钟

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

秒杀,就像是计划经济的菜市场,过客匆匆,你来我往。熙熙攘攘一阵子,过后只留下冷清寂寞的大街。

且看一个卖鹅的故事。↓↓↓

就在昨天。天刚蒙蒙亮,大概是早晨五六点钟,几个程序员顶着蓬松的头发,下班结伴而行。这个时候,街上的路灯还没有灭的干脆。几个锻炼的老大爷,叉着腰,身体前倾,弯成一张弓。

所以,胡同岔口里一个卖鹅的小贩,就显得特别的显眼。就见一大群鹅被关在诺大的笼子里,扑棱着翅膀。有几只精力旺盛的,伸长脖子呱呱叫着,小贩听得心烦,就用手中的树枝敲它们的脑袋。

小贩歪了歪嘴,又用眼角余光扫了下手机,已经五点六十了。就在这时,四面八方就围上来一群大妈,就像是从地底冒出来一样。刚开始还悠然的靠拢,等看到笼子果然有一群鹅,就捏着手里的小包,争先恐后的小跑起来。

这来势汹汹的阵势,吓了大家一跳,程序员们站住不动了。大爷的腰也不弯了,就连那些聒噪的鹅,也不叫了。

很快就有大妈帮小贩打开了笼子,不容分说,扯住一只鹅的脖子就拖了出来。接着就有另外一只手扯住了另一只鹅的翅膀。一下子人喊鹅嘶,吵吵嚷嚷,下起了鹅毛大雪。不一会儿,所有的鹅就都在大妈们手里了。但也有更多没得到鹅的大妈,用手绢在一旁抹着悔恨嫉妒的泪水。

王大妈最高兴了,她手大,抓了三只,其中两只倒霉的鹅被她握在一只手里,脖子拧成一根麻花。也有被捏死的鹅,犯了鹅命的大妈就不想要了,但有更多的大妈根本就不嫌弃。

小贩长吁一口气,招数确实有效,就搞了个秒杀,这群犯了瘟病的鹅,瞬间被低价处理了。

这一切全落在了躲在一旁的程序员们眼里。等人散的差不多了,他们把小贩围上,其中一个眼尖,喊了出来:”这卖鹅的,不是xjjdog么?“

“xjjdog正是在下。我们不如找个油条馆子,坐下来等我给你们,慢慢道来。”

秒杀难点

秒杀,这么酷炫的词语,注定了不是小绵羊,而是洪水猛兽。3w块钱和3000w的系统差别,想要了解一下么?

任何不对等的情况,都会产生危机,对业务系统来说同样的道理。秒杀系统难,主要集中在以下几点。

1、流量超出承载范围
秒杀,一般归作突发流量,平常一天的请求量,可能集中在几秒之内就能完成。秒杀资源的稀缺,也会造成资源成为热点,发生多人争抢的局面。想象一下小长假的高速公路收费站,就能够了解到一无所得的参与者有多火大。

2、资源冲突
如果采用传统的数据库进行数据存储,对同一资源的争抢,就会面临严重的锁冲突问题。一般是通过一个前置的,速度更快的存储顶在前面,这就涉及到源库和目标库的数据同步问题。

从商品资源的上架,到秒杀的完成,会经历一个短暂的混沌状态,出现数据不一致的情况。在请求量非常集中的情况下,还会产生并发问题,个体的行为和结果,是不可预测的。

3、难度高 秒杀对基础设施和技术的要求也是比较高的,从接入层到缓存到存储层,以及安全方面的考虑,需要多个组件的参与,而且每个组件都需要进行优化。

总之,吵吵闹闹一场,最终会归于平静。为了秒杀而准备的硬件资源,不能就放在那里闲置了吧,所以一般还会有一个资源释放阶段,这是后话,我们不做过多关注。

业务三阶段

一般的,秒杀业务会分为三个阶段。其中,抢购阶段,就是我们常说的秒杀业务。

1、准备阶段
在准备阶段,除了硬件和软件系统的准备,一般会有一个活动上的预热,互联网运营会将类似电线杆上小广告的东西,广而发之。从前,有个客户搞了个秒杀活动,100个库存99个人参与,99个人有90个内部员工,尴尬呵呵。

如果有自己的app,通过通知、订阅,会达到比较好的效果。如果涉及的商品多,参与人数巨大,会对数据进行预处理,进行提前预热。一切准备妥当,就可以抽根烟,等着倒计时了。

2、抢购
俗话说,台上一分钟,台下十年功。秒杀开始,会有大量的瞬间请求涌入,该到了上台表演的时候了。这个阶段,我们的每个系统和模块,都会迅速轮转起来,任何一个点考虑不周,都会造成本次秒杀活动的失败,所以关键组件要保证极高可用。

3、结束清算
上面也说过,秒杀会有一个短暂的混沌态。清算阶段,就要完成数据的最终一致性,落库动作可能会持续不少时间。可能有的用户,在付款的那一刻,后悔了,商品要重新归位回仓。回仓后的商品一般会再次售卖,比如火车票,30分钟后可以再抢一次;有的商品就可以被锁定下架,永远消失了。

制约原理

这里,我们大体说一下秒杀系统在技术方面的基本制约原理,详细的描述和代码,我们在后面的章节里进行说明。

数据预热

有的系统进行秒杀的,可能就那么几件商品,手工录入都玩得转。对于平台类型,或者用户量巨大的app,秒杀的商品就不再那么简单。

中间,会进行一些数据的合并,或者二维展开,也就是准备秒杀的数据。这些数据进行处理之后,会提前进入到秒杀系统进行数据预热。

秒杀阶段进行的是否顺利,得看数据准备的是否合理。

请求承载

这是请求的最外层,属于接入层。做的好的系统,能够在接入层就屏蔽大部分请求,极大的减轻后端服务的压力。

连接数承载
对于接入层来说,首先一个挑战就是连接数。一般互联网的接入层,就是lvs+nginx。这里会涉及到对操作系统的优化,以及对于nginx本身的优化。

并发承载 对于落到某台机器上的请求,依然会存在并发高的问题。线程池使用要合理,怎么去进行过滤,合并等,有一定挑战。

负载均衡
请求要能真正的做到均衡,不能产生热点问题。比如nginx的ip_hash,虽然能一定程度上规避分布式session问题,但请求会不均衡。

重试?
秒杀业务不要配置重试,会加剧系统负载。请求失败?那就再来一次。

系统隔离
秒杀业务占用的系统资源,和正常运行的系统严重不对等。如果有条件,秒杀系统的硬件和服务环境,要与正常业务系统进行一定程度的隔离。要提前评估对其他服务的压力,避免影响正常业务。

CDN
对于html,js,css,图片等内容,占用了大量的带宽。如果将这些资源都放在自己的服务器上,流量到来时会迅速占满带宽,造成正常的秒杀请求无法完成。CDN可以有效解决这个问题。剩下的请求,就是真正的秒杀业务。

减小请求包
对网络请求包,要进行大量优化。可以开gzip压缩,资源本身也进行压缩,去掉请求包中的无用信息,对网络报文进行精简。

请求拦截

秒杀系统一个非常大的原则,就是要把尽量多的无效请求,拦截在外部。请求拦截,可以分为上游拦截和业务拦截。

上游拦截
拦截方面,存在一个全局的设置。当系统判断以及达到瓶颈阶段,就可以通过全局限流方式进行服务降级,对于一些次级服务,要进行熔断处理。对于前端来说,也是需要进行一些优化的。比如浏览器缓存,防重入验证等,能够拦截数量可观的请求。

业务拦截
除了一些全局的限制,对于大部分请求来说,和用户是息息相关的。一个用户,可能会频繁的刷新,或者绕过前端,直接使用软件调用后端接口。这些用户的非法请求,也要进行拦截。

同时,用户对资源的争夺,也不应该无限等待。比如100个库存的商品,第1w个请求到来的时候,就不需要再排队等待了,直接返回秒杀完毕就ok了。

排队方面,会用到jvm内排队,也会用到外部的消息队列,mq,进行请求的缓冲。

数据缓存

缓存,可能是秒杀系统中最重要的一个组件了。从前端缓存,到jvm缓存,再到分布式缓存,都会对系统性能产生数量级的提升。值得注意的是,由于秒杀系统严重依赖缓存系统,所以缓存系统需要做高可用。

缓存的读操作,要考虑数据的加载和同步。写请求,就要考虑数据的合并与并发写入,数据的一致性等。虽然缓存的速度比起DB来,快了很多很多,但它的性能总是有瓶颈的,相关代码要着重优化。

安全

技术的门槛越来越低,二年级的小学生都开课教swift了,写个秒杀插件什么的,不费吹灰之力。秒杀系统的安全性比较重要,应该说和钱打交道的系统,都是容易出问题的。你要是想薅羊毛,认准营销、秒杀业务,准没错。

要尽量提高作弊门槛,比如url动态化,从入口就隔绝了大部分攻击;验证码,只会增加攻击者的成本。有些安全性级别较高的,还会增加风控规则,比如同一ip请求过多封禁、账号注册日期三天之内不允许参与、秒杀的门槛必须是金牌会员等。

我曾经经历过一次,对方本来是一个算加减乘除的验证码,脚本都写好了。结果秒杀前5分钟,验证码12306附体,xjjdog直接放弃了。

躲在幕后的DB

在整个秒杀系统中,传统的DB,只能灰溜溜的躲在幕后(小流量除外)。我要是DB,也会躲在后面瑟瑟发抖。

DB的数据,要提前载入到秒杀系统中进行运算,秒杀完毕,还要把狼藉的数据进行落地与清算。在笔者见过的不少秒杀场景中,甚至不需要DB的参与,真是艺高人胆大。

这就引申出另外一个问题。假如缓存系统出现问题,请求要不要穿透呢?我的建议是,不需要。非正常的请求,会瞬间压垮DB,产生更加严重的数据错乱问题,假如没有做隔离,后果会更狂野。与其错了,不如认怂,乖乖的复盘写故障报告吧。

End

秒杀,夺宝,p2p,是互联网创造的,钱袋子三大杀手。

我要说一些隐秘的事情。前不久,我的这群鹅本来好好的,结果混进一只长了瘟病的鸡,没几天就病恹恹的不行了,要是扔了怪可惜的。这卖鹅的时间线,也搞的十分紧凑。

就在昨天,我就放出了有一批廉价鹅要处理的消息。为了让更多的大妈相信,我按照市面价格打了个五折,其实打一折都能出手(抖音上那种鹅不敢卖)。5点多我就给几只快不成的鹅,注射了兴奋剂,希望它们能多撑一会,还拿了根树枝敲它们的脑袋进行确认。不是我自信,这种场景,就是死鹅也卖得出去。但死的多了,毕竟不好。为了限制拥挤的人流,我特意把笼子口的铁丝角给漏出来,不少大妈划破了手都没把鹅抓到,我也搞不清她们是不幸,还是幸运。

是谁首先创造的秒杀?真是天才。和饥饿营销一样,收的是智商税吧。哈哈哈~

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,​进一步交流。​