秒杀场景需要考虑这些关键词:高并发、响应时效性、流程削峰、恶意流量攻击、秒杀原子操作与数据安全、服务高可用(应对雪崩)等。
面试题:设计一个10000并发的秒杀方案,9.9秒内秒杀100个商品。
① 秒杀/抢购业务场景
比如商品秒杀、商品抢购、群红包、抢优惠券、抽奖等等。
② 秒杀/抢购业务特点
秒杀商品价格低廉、抢购商品很好|抢手、大幅推广|广为人知、瞬时售空、一般是定时上架、持续时间短、瞬时并发量高等。
③ 秒杀/抢购技术特点
高并发、读多写少、资源冲突(容易导致超卖问题)。
削峰利器-异步MQ
如下所示,将用户请求通过消息中间件转发到秒杀服务器,通知秒杀系统一个个处理。
队列
可以使用Java内部队列来控制用户请求并保证公平性–先到先得,然后将队列转发给秒杀系统处理。
④ 系统基本架构与秒杀配套解决方案
不同于OSI的七层架构模型,这里应用系统架构分为五层,如下所示:
其中按钮控制、图形验证码是为了尽可能屏蔽恶意流量,比如机器人请求、脚本自动请求。
① 秒杀人群、并发规模的预估
为什么要估算?当然是为了确定一个最终的技术选型以及服务器容量。
那么如何估算呢?
平均并发用户数为C=nL/T,秒杀的并发规模就要根据公司活动历时以来的最高峰值再扩容。
② Nginx限流算法
常见限流算法有"漏桶算法"和“令牌桶算法”,Nginx提供了一个叫ngx_http_limit_req_module的模块进行流量控制,Nginx是基于漏桶算法实现。
③ 从前到后流程示意如
④ 乐观锁和悲观锁
乐观锁如使用version控制,悲观锁则如Select count from tb_goods where id=1 for update
。
在高并发秒杀场景中,乐观锁是不太适合的。因为其冲突频率、重试代价所带来的性能消耗是大于悲观锁的。
① 页面/静态资源的优化
动态页面静态化其实就是将传统的jsp或者thymeleaf、freemarker转换HTML+AJAX。静态页面可以缓存到客户端(比如浏览器),通过AJAX发送请求获取数据然后渲染页面。
静态资源优化
页面缓存
比如使用thymeleaf时,把页面缓存到redis一段时间,前端请求过来时先去redis获取页面。代码示例如下:
//取缓存,如果有直接返回
String html = redisService.get(GoodsKey.getGoodsDetail, ""+goodsId, String.class);
if(!StringUtils.isEmpty(html)) {
return html;
}
//如果没有就生成并放入redis
SpringWebContext ctx = new SpringWebContext(request,response,
request.getServletContext(),request.getLocale(), model.asMap(), applicationContext );
//后台自己解析页面并缓存起来
String html = thymeleafViewResolver.getTemplateEngine().process("goods_detail", ctx);
if(!StringUtils.isEmpty(html)) {
redisService.set(GoodsKey.getGoodsDetail, ""+goodsId, html);
}
通常现在项目中都是采用前后端分离模式开发,比如前端的VUE。那么部署的时候采用动静分离分别部署即可。
参考博文:Java 高并发解决方案(电商的秒杀和抢购)