目录

初步思考

秒杀活动

订单防止超卖

订单超时如何处理


初步思考

原文地址

前端:页面尽可能静态化,css/js合并,减少请求数

扩容:增加机器,提高处理请求能力

限流:应用限流(nginx,tomcat设置线程池,最大请求数),服务限流(限流算法,令牌桶/漏桶),MQ堆积消息,用户请求限制(单位时间内访问接口次数)【主要保证每台机器能够处理自己能力之内的任务】

使用多线程开发,提高机器处理能力

动静分离

1、数据拆分

动静分离的首要目的是将动态页面改造成适合缓存的静态页面;第一步就是分离出动态数据,主要从以下两方面进行:

  • 用户,用户身份信息包括登录状态及登录画像等,通过动态请求获取;
  • 时间,秒杀时间是由服务端统一管控的,可以通过动态请求获取;

2、静态缓存

剩下的数据是静态数据,例如商品信息,商品图片,页面js/css等等,进行合理的缓存(生成静态页面)

静态数据缓存到哪里?浏览器,CDN,服务端

用户从CDN获取到静态数据

秒杀活动

秒杀一般在12306抢票或者电商举行的一些活动时遇到。对于一些稀缺或特价商品,电商网站一般会在约定时间点,在秒杀页面对其进行限量销售。

秒杀相关特点:

  • 秒杀时大量用过户会在同一时间同时进行抢购,网站瞬时访问流量激增。(高并发)
  • 秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功。(防止超卖现象)
  • 秒杀业务流程,下订单,减库存,支付(秒杀肯定是为了商品,一般不会有订单过期,取消订单,增加库存)

从架构视角来看,秒杀系统本质是一个高性能、高一致、高可用的三高系统。

设计流程

1、限流
2、将库存放到redis中、接收用户请求的时候。从redis取库存,判断库存量是否大于本次订单购买量
   库存大于本次购买量:扣减redis中的库存、并且将订单信息推送到MQ;
   库存小于本次购买量:直接返回、数量不足。
3、MQ消费者获取消息:
   1):更新数据库库存(乐观锁)
   2):生成订单信息,扣除用户账户的订单金额(余额不足的话、将本次购买量加回到库存里)
   3):异步通知用户购买结果。

原文地址

令牌机制实现秒杀业务(推荐)

利用定时任务将某些商品在规定时间之后要开启秒杀,根据库存量同步到Redis中。根据每一个商品产生对应的token数量,采用Redis中的List数据类型存储每个商品的令牌。(采用List数据类型存储的原因主要是每一个线程从List中pop时是单线程处理的,所以每一个线程拿到的令牌就不可能是同一个了)
在秒杀期间,每一个用户都去获取对应商品中的令牌(判断令牌是否有效-非空判断,如果是已经被支付过的token就不能再次被抢购)
超时未支付,归还令牌 支付成功,产生订单,标记当前令牌已经被支付,同时删除当前令牌。

原文链接

订单防止超卖

现象

  • 不同用户在读请求的时候,发现商品库存足够,然后同时发起请求,进行秒杀操作,减库存,导致库存减为负数;
  • 同一个用户在有库存的时候,连续发出多个请求,于是生成多个相同订单;

原因

数据库底层的写操作和读操作可以同时进行;写操作默认带有隐式锁,但是读操作默认是不带锁的;所以当用户1去修改库存的时候,用户2依然可以都到库存为1,所以出现了超卖现象。

方案分析

(1)Sql限制

在更新数据库减少库存时,进行库存限制条件(排他锁,也就是写锁起到了作用)

并采用数据库乐观锁(version版本号,CAS原理),如果限定条件不满足或版本号不一致就无法成功;

update table set count=count-1,version=versiono+1 where version=version and (count-1)>0;

(2)使用Redis对列实现

将要促销的商品以对列的方式存入Redis中;每当用户抢到一件商品则从队列中删除一个数据,以确保商品不会超卖。(将多线程变为单线程读写)

(3)使用Redis原子性操做命令(decr,incr),移除后同步更新数据库记录;

(1)数据库加唯一索引限制

对于生成多个相同订单,在UserId和OrderId上加唯一索引。

订单超时如何处理

原文地址

在开发中往往会遇到一些延时任务的需求

  • 生成订单30分钟未支付,则自动取消
  • 生成订单60秒后未支付,给用户发短信

延时任务和定时任务的区别在哪里呢?

  • 定时任务有明确的触发时间,延时任务没有
  • 定时任务有执行周期,而延时任务在某事件触发后一段时间内执行,没有执行周期
  • 延时任务一般是单个任务

方案分析

(1)数据库轮询

通过线程定时的去扫描数据库,通过订单时间来判断是否有超时订单,然后进行操作。

使用场景:小型项目

缺点:存在延迟(定时任务扫描的间隔),严重影响数据库性能(假如数据量过大,每几分钟扫描一次,影响其他业务)

(2)JDK延时对列

JDK自带的DelayQueue,是一个无阻塞队列,该队列只有在延迟期满的时候才能从中获取元素。放入DelayQueue中的对象,是必须要实现Delayed接口的。

方法:

  • poll():获取并移除队列的超时元素,没有则返回空。
  • take():获取并移除队列的超时元素,如果没有则wait当前线程,直到有元素满足超时条件,返回结果。
package com.test.thread;import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;public class OrderDelay implements Delayed {private String orderID;private long timeout;public OrderDelay(String orderID, long timeout) {this.orderID = orderID;this.timeout = timeout;}/* 返回距离你自定义的超时时间还有多少 */@Overridepublic long getDelay(TimeUnit unit) {return timeout - System.currentTimeMillis();}@Overridepublic int compareTo(Delayed o) {if (o == this) {return 0;}OrderDelay t = (OrderDelay) o;long d = getDelay(TimeUnit.SECONDS) - t.getDelay(TimeUnit.SECONDS);return d > 0 ? 1 : 0;}public void execute() {System.out.println(orderID + "\t订单要被删除啦");}public static void main(String[] args) {LinkedHashMap<String, Integer> contains = new LinkedHashMap<>();contains.put("order_0", 5);contains.put("order_1", 4);contains.put("order_2", 10);contains.put("order_3", 12);DelayQueue<OrderDelay> queue = new DelayQueue<>();System.out.println("任务添加到延时队列中");for (Map.Entry<String, Integer> entry : contains.entrySet()) {queue.put(new OrderDelay(entry.getKey(), (1000 * entry.getValue() + System.currentTimeMillis())));}long start = System.currentTimeMillis();while (true) {try {queue.take().execute();System.out.println("执行时间:\t" + (System.currentTimeMillis() - start));} catch (InterruptedException e) {e.printStackTrace();}}}
}

优点:效率高,任务触发时间延迟低

缺点:数据存储在内存中,服务器重启,数据丢失;内存限制(订单过于庞大);

(3)时间轮算法

用Netty的HashedWheelTimer实现

package com.test.thread;import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;import java.util.concurrent.TimeUnit;public class HashedWheelTimerTest {static class MyTimerTask implements TimerTask {boolean flag;public MyTimerTask(boolean flag) {this.flag = flag;}@Overridepublic void run(Timeout timeout) throws Exception {System.out.println("删除订单");this.flag = false;}}public static void main(String[] args) {MyTimerTask timerTask = new MyTimerTask(true);Timer timer = new HashedWheelTimer();timer.newTimeout(timerTask, 5, TimeUnit.SECONDS);int i = 1;while (timerTask.flag) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(i + "秒过去了");i++;}}
}

优点:效率高,代码复杂度比DelayQueue低,任务触发时间延迟比DelayQueue低

缺点:数据存储在内存中,服务器重启/宕机,数据丢失;内存限制(订单/任务数过多);

(4)Redis缓存

Redis的zset是一个有序集合,每一个元素都关联了一个score,通过score排序来获取集合中的值。

实现:将订单超时时间戳与订单号分别设置为score和member,系统扫描第一个元素判断是否超时。

(5)使用消息队列

RocketMQ延时消息(只支持特定级别的延迟消息,1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h)

RabbitMQ有延时对列

秒杀活动,提高性能,防止超卖,订单超时相关推荐

  1. 【Java秒杀方案】11.功能开发-【商品秒杀及优化】防止超卖 接口优化(redis预减库存,内存标记减少redis访问,RabbitMQ异步下单) 安全优化(隐藏秒杀接口,验证码,接口防刷)

    商品秒杀核心功能及优化 1. 正常秒杀流程 在商品详情页面等待秒杀倒计时–http://localhost:8080/goodsDetail.htm?goodsId=2 倒计时为0,开始秒杀,点[秒杀 ...

  2. 秒杀 mysql 事务_秒杀怎么样才可以防止超卖?基于mysql的事务和锁实现

    Reference:  http://blog.ruaby.com/?p=256 并发事务处理带来的问题? 相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从 ...

  3. java秒杀怎么防止超卖_秒杀系统是如何防止超卖的?

    秒杀系统介绍 秒杀系统相信网上已经介绍了很多了,我也不想黏贴很多定义过来了. 废话少说,秒杀系统主要应用在商品抢购的场景,比如: 电商抢购限量商品 卖周董演唱会的门票 火车票抢座 - 秒杀系统抽象来说 ...

  4. 淘宝如何解决超卖问题

    这篇文章是我从某文库爬下来的,放在这里供大家学习. 淘宝超卖现象的产生及解决方案 一.什么是超卖现象?  超卖即"超卖缺货",当宝贝库存接近0时,如果多个买家同时付款购买此宝贝,将 ...

  5. 【Redis】实战篇:优惠卷秒杀 (库存超卖问题、一人一单问题)

    文章目录 3.1 全局唯一ID 3.2 -Redis实现全局唯一Id 3.3 添加优惠卷 3.4 实现秒杀下单 3.5 库存超卖问题分析 3.6 乐观锁解决超卖问题 3.7 优惠券秒杀-一人一单 3. ...

  6. php 有关秒杀防止超卖面试题

    秒杀,怎么防止库存超卖 所谓秒杀,就是网络卖家发布一些超低价格的商品,所有买家在同一时间网上抢购的一种销售方式.由于商品价格低廉,往往一上架就被抢购一空,有时只用一秒钟. 先来就库存超卖的问题作描述: ...

  7. 用分布式锁来防止库存超卖,但是是每秒上千订单的高并发场景,如何对分布式锁进行高并发优化来应对这个场景?

    用分布式锁来防止库存超卖,但是是每秒上千订单的高并发场景,如何对分布式锁进行高并发优化来应对这个场景? 转载 codeing_doc 最后发布于2018-11-23 09:44:41 阅读数 1073 ...

  8. Redis高并发场景下秒杀超卖解决

    目录 1 什么是秒杀 2 为什么要防止超卖 3 单体架构常规秒杀 3.1 常规减库存代码 3.2 模拟高并发 3.3 超卖现象 3.4 分析原因 4 简单实现悲观乐观锁解决单体架构超卖 4.1 悲观锁 ...

  9. 分布式商城系统架构中的超卖问题深度剖析(从问题原因到解决方案到优化总结)以及重复下单问题

    超卖问题(包含重复下单问题) 背景 首先,超卖问题的出现是由于高并发环境下,大量秒杀请求同时发给服务端导致的秒杀商品的销售数量>其库存数量的问题.其本质就是并发场景下,多线程或者多进程对共享资源 ...

最新文章

  1. 新电脑一般javaweb配置
  2. java实现metro风格_Metro风格的Java组合框(JMetro)–重新介绍
  3. 百度相关搜索软件_不太热门的办公神器软件篇搜索相关
  4. 判断form表单里面的元素属性是否有数据_html form标签的action属性是什么意思?又有哪些用法?(附实例)...
  5. 多线程学习-时间改变事件
  6. Radon变换——MATLAB
  7. DIY新浪微博Android手机客户端
  8. linux装在机械硬盘怎么样,电脑装了固态硬盘还能再装机械硬盘吗
  9. 强收红包漫天要价偷转黑车……滴滴网约车被指太任性
  10. 51单片机的一点感想
  11. python复利计算_python复利代码
  12. Java数据可视化 (JavaFX, Apache ECharts)
  13. windows 环境下node开发环境搭配问题
  14. java开发中常见的延时消息解决方案
  15. jenkins内部分享ppt
  16. [从零学习汇编语言] - BX寄存器与loop指令
  17. 升华思想境界,走出博士的专家路线【转帖】
  18. qt小项目 代码实现简易的QQ聊天 对话框的界面实现
  19. jsWeb Apis 05
  20. ADIS16400/ADIS16405带磁力计的三轴惯性传感器(1)

热门文章

  1. 谈谈本地缓存的几种方式以及他们的区别?
  2. js手动触发页面元素点击事件,程序触发,自定义点击事件模拟点击
  3. 凡泰极客「开放银行」主题私享会圆满落地
  4. 微信网页开发——JS-SDK接入以及微信二次分享图标和标题丢失
  5. 谷歌、亚马逊、IBM和微软的云计算平台
  6. 学习笔记二.矩阵按键
  7. HDOJ 3723 Delta Wave
  8. Cadence OrCAD Capture 原理图中预览元件封装技巧图文教程
  9. 盘点几位史诗级黑帽黑客:这群人到底厉害到什么程度?
  10. GsyVideoPlayer视频分析使用