阐述秒杀的过程

秒杀

秒杀就是商家为了宣传,开启的一种限时、限量的活动。他的特点是:短时间内的高并发

一般的秒杀类型:

分批次秒杀(限时)(小米、京东);
限量秒杀(2件)

所以要做好一个秒杀系统,我们一般需要做以下几方面考虑:
1、独立服务器部署;(不影响网站其他功能的正常运行)
2、页面的静态化;(商品短时间内访问量大,不能每次都去后台获取数据)
3、CDN加速;(增加异地用户访问速度)
4、redis防止超卖;(高并发)
5、MQ做订单的慢处理;(秒杀当时,订单量很大,如果每个订单都实时操作数据库,处理不过来)
6、nginx、MQ限流;
7、集群部署;

具体实现步骤:(以京东为例)
1、运营管理平台发布秒杀批次;
批次表:(主键id,批次主题、开始时间、结束时间、创建时间、状态(0未开始、1进行中、2已结束);
2、商家报名批次,添加参与秒杀的商品;
秒杀商品表:(主键id,skuid、sku名称、秒杀价格、原价格、库存,批次id(1对多));
如果商品和批次想要做多对多,可以把批次id用,分割。或者做中间表
3、运营管理平台审核秒杀商品;审核通过;
a、用freemarker模板生成商品秒杀详情页面;
b、把秒杀商品库存放入到redis数据库里边,用固定前缀“JDMS"+秒杀商品id做key,库存做value;
4、门户秒杀商品根据批次进行展示;(只展示当天的、用tab页展示,默认选中,当前正在“进行中”的;已结束的显示(已结束),进行中的(显示倒计时);未开始的显示(即将开始);
a、倒计时的实现: 倒计时需要通过前段js的定时任务实现(setTimeOut只执行一次setInterval没隔多少秒执行一次;)需要注意的是,倒计时是根据系统当前时间和批次的开始时间的差值进行计算的。 这里的系统时间,必须是服务器时间;通过java代码获取,而不能在js里边获取;
5、商品详情页,要注意以下几个问题:
a:里边有些数据是动态的;(比如:库存)
b、在秒杀开始前,防止用户通过f12直接获取到秒杀路径,提前购买;
解决方案:用动静分离的方法解决;把html和js分开(1批秒杀商品共用1个js,每个商品1个单独html页面); 页面上的动态数据(库存)和按钮(事件)都写在js里边。在秒杀没有开始之前,js按钮事件里边什么都没有;再服务器后台通过定时任务扫描批次表,如果秒杀时间到了,通过freemarker生成一个新的js,替换掉原来的js。这个新的js里边就包含了(秒杀路径); 定时任务除了负责生成新的js以外,还要负责修改批次状态;同时把当前秒杀的批次id、放入redis。用自定义字符串做key;
6、开始秒杀后,用户点击抢购按钮:用ajax方式提交到后台,传入秒杀商品id和批次id; 请求首先经过nginx;再进入我们的代码中;这里我们可以通过nginx做集群、负载均衡和限流;
7、后台秒杀代码: 接收秒杀商品id和批次id;
第一步验证:首先,把redis中的秒杀批次id和传入的秒杀批次id做对比。如果一样,表示是当前正在秒杀的商品;再往下进行;
第二步验证:用固定前缀“ms”+用户id+商品id,去redis里边获取;如果有值,说明已经改用户已经秒杀过改商品,不能重复秒杀;如果没有往下进行:;
第三步: 调用redis库存的自减方法;key=固定前缀“JDMS"+秒杀商品id;返回值如果>=0;说明购成功,否则购买失败。由于redis是单线程。所以这里不存在并发问题。也就是说,不可能出现自减到负数的情况(超卖);如果购买成功:,那么就用固定前缀“ms”+用户id+商品id做key,存入redis里边。value设置为1;
第四步,如果成功,返回用户true,如果失败返回false;
8、秒杀前台js,ajax提交秒杀根据返回值判断,如果false直接提示用户秒杀失败;可以重新秒杀;如果成功,直接弹出商品订单页面,让用户补全收货地址信息,发起支付;
9、用户点击支付; 提交补全信息,到后台,把补全信息存入redis里边;替换固定前缀“ms”+用户id+商品id做key的vlaue;然后跳转到支付宝支付页面;用户进行支付。支付成功后,支付宝回调我们服务器,通知我们结果;
10、在支付回调方法里边,我们如果接到支付成功的通知;那么就给MQ发送1条消息。通知订单后台去生成真正的订单,操作mysql数据库; (由于并发量比较高,MQ处理消息比较慢,所以可能出现用户今天下单成功,但是这个订单第2天才通过MQ生成到了数据库里边。商家才看到订单,开始发货)
问题1:如何保证redis不宕机,从而丢失用户订单?
redis持久化和集群;
问题2:如何保证MQ消息的可靠性送达?
1、保证消息一定能放入MQ队列中;
解决方案: 开启事务(对MQ效率影响很大)
confirm确认(普通确认(比事务好一定,但不明显)、批量确认、异步确认(最常用));
2、保证消息在队列中不会丢失;
开启消息的持久化
3、保证消费者消息一定能被消费?
开启消息的ack机制;
4、开启ack可能导致消息重复消费,如何解决?
给消息生成1个随机唯一id;在消费端,用这个唯一id做分布式锁;保证只能消费一次;
问题3: 如果用户秒杀成功以后,放弃支付,那么这时候,redis库存已经减掉,如何把库存从新加入redis?
解决方案:1、可以不考虑存放。因为只要用户参与了秒杀,从一定程度上来说,宣传目的已经达到。少赔本卖1件,影响不大;
解决方案2: 可以通过redis过期监听实现。redis中的虚拟订单设置有效时间,如果用户在规定时间内没有支付,那么订单就会过期。在java里边可以写一个redis过期监听类,在key过期时,这个方法会自动触发,获取到过期的key,判断如果是虚拟订单的key,就根据这个key里边的商品id,调 用redis库存key的自增方法,把库存加上。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值