什么是秒杀
秒杀场景一般会在电商网站举行一些活动或者节假日在12306网站上抢票时遇到。对于电商网站中一些稀缺或者特价商品,电商网站一般会在约定时间点对其进行限量销售,因为这些商品的特殊性,会吸引大量用户前来抢购,并且会在约定的时间点同时在秒杀页面进行抢购。
秒杀系统场景特点
- 秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激增。
- 秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功。
- 秒杀业务流程比较简单,一般就是下订单减库存。
解决高并发(秒杀),我们应该从前端,后台统筹考虑,下面详细讲解具体实现方式:
一 . 前端优化
1. 采用动静分离架构(前端优化核心)
动态数据(后台代码)一般放在ECS等云服务器,静态数据(js/css/img实现压缩减少带宽的传输)放入七牛云或者阿里云OSS等第三方资源服务器,并使用CDN加速,从而减少客户端与服务端带宽传输。
如下图所示一般详情页的图片是不变的,可以直接在页面写死即可,如果想做成动态的,只要保证后台数据库商品图片存的路径为oss即可,这样可以减少图片传输所占用的带宽。
**2. 防止重复提交:**提交后按钮disabled,防止用户重复提交
**3. 商品详情页面:**使用Nginx+Lua+OpenResty实现商品详情页面的优化(需要掌握lua语言,不在本文讨论范围内)
二. 后端优化
1. 基于乐观锁/redis锁,防止库存超卖
这里拿乐观锁举例,redis锁原理都是一样的
① 不加版本号的行级悲观锁(多个用户操作一个商品,线程本身就是安全的,因为数据库默认开启行级锁)
@Update("update goods_table set inventory=inventory-1 where inventory > 0 and goods_id=#{goodsId}")
int inventoryDeduction(@Param("goodsId") Long goodsId);
② 带版本号的乐观锁(数据库需单独新增一个version字段,每次调接口,version加1)
@Select("SELECT order_id,goods_name,inventory,create_time,version from gooods_table where goods_id=#{goodsId}")
GoodsDto getByGoodsId(@Param("goodsId")Long goodsId);
@Update("update goods_table set