秒杀系统难做,是因为库存有限,很多人会在集中的时间内读写有限的数据,在短时间内,系统会面临成千上万倍的流量进入。那么如何能做好秒杀系统呢?我认为核心思想有这么两点:
-
将请求尽量的在上游环节就拦截住(不要轻易到数据库这一级)
-
充分利用缓存
那么这两点如何实现呢,下面详细说说:
-
最上层是客户端层,常见的都是浏览器访问。点击一次【秒杀按钮】,然后再点一次【秒杀按钮】,那么是访问了两次后端系统么?如果用户手速快一些的话,或者用第三方插件不停的点击,那么岂不是多出来很多请求。从产品层面,我们会设置点击一次按钮后,将按钮置灰,从技术角度,我们可以通过JS控制几秒内只能提交一次请求。看,这就是“将请求尽量的在上游环节就拦截住”。
-
当然客户端层做限制,对于在座的程序猿们都是小意思,因为一抓包,请求长什么样子一清二楚,然后写个脚本,循环调用就好了;为了防止这样的情况发生,后端的服务需要做去重的工作。比如按照用户名去重,在N秒内,只允许1个请求访问进来,然后做页面缓存;比如10秒内发送了一万次请求,其中1次请求访问成功并返回了页面,将这个页面进行缓存,剩余9999次请求直接返回这个缓存页面。
-
再往下走,10秒内一个客户只有一次请求进来,但是如果同时有一百万个客户,那么这10秒内也有有一百万次访问,那么如何应对呢?用【消息队列】,所有的请求过来,都排队吧,每次只让有限的请求去访问数据。
-
当然访问数据也不是直接去读写数据库,这里还有一层数据缓存,比如可以使用Memcached或者Redis缓存库存剩余,通常在秒杀系统中,这个“库存”可以是粗粒度的,也就是说这个数字可以是不准确的,客户关心的是买到还是买不到,而不会关心剩余数量到底是20件还是10件;数据读操作也可以放在缓存中,再由缓存和数据库做数据同步。
-
上面几步已经拦截了大多数的请求,到DB这一层的时候,基本上没有什么压力了。
秒杀是电商企业最吸引流量,也是最考验技术的场景!
秒杀的系统设计其实遵循“倒金字塔”原理,就是从前端页面,网络,到后端服务,数据库,一一的将请求滤掉,最终让落在数据库的数据都是满足要求的有效数据,假设是100万人参加1000台机器的秒杀,即是设计100万-->1000的过滤系统;
要达到这样的目的通常有下列的手段:
①,前端页面防重复刷:点击一次后,按钮置灰,在指定时间内只允许抢一次!
②,控制网络流量暴增:将前端页面放置在CDN节点,防止网络流量压力快速增大;
网关进行限流:使用nginx 进行网关限流!
通过设置nginx参数limit_conn_zone ,limit_req_zone ,ngx_http_upstream_module进行限流!
③,后端应用服务:
1,如果没有使用nginx限流,可使用spring-cloud-zuul进行网关限流!
2,异步处理 :防止同步调用带来的阻塞,包括数据落库等都可以使用异步调用!
3,缓存: 最重要的一步,可以事先将要秒杀的商品id进行缓存,使用分布式锁获取到id和对应的userid进行绑定,才算秒杀成功,然后异步保存数据!
使用redis的watch对同一个账号进行限制;
④,数据库系统: 使用读写分离 ,分库分表 等手段提升数据库系统的吞吐量!