轻松搞定高并发秒杀

1、背景

  • 秒杀通常都是定时上架的 不少人抢 不停的刷新 
  • 瞬间流量暴涨  商品瞬间卖完 要担忧超卖问题
  • 查询商品->建立订单->扣减库存->更新订单->付款->卖家发货   大部分过程短期完成

2、隔离

2.1 业务隔离

        秒杀活动只是网站营销的一个附加活动,这个活动具备时间短,并发访问量大的特色,若是和网站原有应用部署在一块儿,必然会对现有业务形成冲击,稍有不慎可能致使整个网站瘫痪。css

  • 独立部署 (集群隔离)
  • 域名隔离

2.2 数据隔离

        秒杀大部分使用的都是热数据,能够启用单独的cache集群 和 mysql 集群  数据还须要预热 提早用程序写到缓存里面mysql

2.3 动静隔离

  • 静态资源都放在CDN上 
  • 把整个页面Cache在用户浏览器 强制刷新整个页面,再请求到CDN (这样把90%的静态数据缓存在用户端或者CDN上,当真正秒杀时用户只须要点击特殊的按钮“刷新抢宝”便可,而不须要刷新整个页面)
  • 只有动态请求才能打到服务器上

 

3、多级缓存

3.1 浏览器缓存

静态页面直接缓存到浏览器中nginx

3.2 CDN缓存

静态资源放到CDN上  并申请扩大CDN带宽web

3.3 nginx缓存

静态资源也能够缓存到nginx上redis

3.4 本地缓存

不用动态更新的商品信息 , 配置数据能够提早缓存到web服务内存中sql

3.5 Redis分布式缓存 

商品库存, 商品信息 ,用户信息 等能够放到redis里面。数据库

4、流量削峰

4.1 基于时间分片削峰

        秒杀的流量走势在秒杀开始的时候会瞬间达到峰值 一柱擎天,对系统的压力很大 , 能够在点击秒杀的时候 加入验证码 答题等方式 强行平滑一波曲线。浏览器

4.2 基于队列削峰

      能够吧请求放入到kafka等队列中,使用消费者控制消费速度。缓存

5、限流熔断

5.1 Nginx 限流

  • 能够针对IP进行漏桶限流 容许必定程度的并发
  • 能够针对IP进行链接数的限流

5.2  Hystrix 限流

  • 须要对下游的服务进行限流 不然可能会形成服务雪崩
  • 对限流的流量能够直接作未秒杀成功的处理 反正他们也不知道

6、防止超卖

         秒杀流量异常巨大,用数据库扣减库存(不管乐观锁、悲观锁) , 悲观锁会形成大量的事务阻塞在mysql,可能会致使整个系统不响应。乐观锁想须要获取一下版本号,而后大并发的更新同一行。虽然mysql 企业版提供了线程池排队插件(要钱的),可是依然没法知足好几万QPS的要求。tomcat

       比较好的方法  库存保存在redis中,使用redis lua 脚本 + kafka落地mysql 。 

       为何要用redis + lua ?

       redis 速度快,lua 实现原子性。  下面代码不具有原子性。

int 库存 = redis.get(key);
if(库存 > 0){
  redis.decr(key)
}

    redis 须要开启AOF持久化 ,可是毕竟是异步复制,因此仍是须要经过kafka 落地到mysql 里面的。

若是lua 脚本返回0  , 标识秒杀结束 , 修改内存中的标志位。 后续请求所有做废。

7、 优化

7.1 web容器优化

    tomcat jetty 其实不太适合瞬时高并发应用, 可使用undertow 基于NIO实现 吞吐量更高。

7.2 nginx 优化

   连接数 , 线程数 能够配置的更高

7.3 模板引擎优化

   通常秒杀页面的首页(其实里面内容不多,就css,js连接)须要模板引擎渲染,可使用beetl ,

而且将渲染内容缓存。

8、安全性考虑

8.1 如何防止直接拿到下单URL? 

        为了不用户直接访问下单页面URL,须要将改URL动态化,即便秒杀系统的开发者也没法在秒杀开始前访问下单页面的URL。办法是在下单页面URL加入由服务器端生成的随机数做为参数,在秒杀开始的时候才能获得

8.2 如何控制秒杀按钮点亮?

     使用js控制 ,js内容true、fasle,该js连接带随机版本号不被缓存,这个js很小 不会对形成影响。 

相关文章
相关标签/搜索