/SpikeExample

秒杀项目迭代

Primary LanguageJavaApache License 2.0Apache-2.0

SpikeExample

介绍

构建秒杀相关内容。项目包含三个模块:

  1. 注册登录。
  2. 商品详情模块。
  3. 下单交易模块.
  4. 限流削峰模块
  5. 秒杀模块

注册 登录 查询商品详情迭代流程

  1. 优化tomcat
    1. spring-configuration-metadata.json文件下,有tomcat相关配置,可修改相关配置增加tomcat的并发量
      1. spring-tomcat-accept-count:默认长度为100 等待队列长度
      2. spring-tomcat-max-connection:最大可连接数,默认为10000
      3. spring.tomcat.max-threads:最大工作线程数。默认200
      4. spring.tomcat.min-spare-threads:最小工作线程数,默认为10
    2. 自定义WebServerConfiguration
    3. 目前局限:
      1. 不能过分提高进程调度线程数。因为提高的越多,就会花费很多时间在CPU调度上。
      2. 目前局限:等待队列长度不能无限长,消耗内存,出队入库也耗内存。
  2. 水平扩展。增加nginx,
    1. web服务器
      1. 实现横向扩容 => 静态资源配置nginx服务器上,通过指定路径访问(如注册页面,商品详情页面)
    2. 反向代理服务器
      1. 设置upstream server
      2. 设置动态请求为proxy pass 路径
    3. 动静分离服务器
      1. 静态资源直接访问nignx
      2. 动态资源直接访问nignx代理的服务器
    4. nignx 高性能原因
      1. epoll机制。变更触发回调直接读取。理论无上限。
      2. master-worker机制。master进程管理worker进程
      3. 协程机制。依附于线程的内存模型,切换开销小。遇到阻塞归还执行权,代码同步,无需加锁。
  3. 使用redis 实现分布式会话,前期使用tomcat容器的session,后期考虑app,小程序等使用token
  4. 缓存
    1. Redis缓存。单机版。sentinal哨兵模式。集群cluster模式。
    2. 热点本地缓存Guava。可控制大小和超时。可配置lru策略。线程安全。
    3. 使用nginx 增加 lua缓存(借用lua的协程机制)=》 openrestry 配合redis 进行网络缓存 =》 引入静态资源CDN =》全局静态资源CDN。
      1. nignx协程。
        1. nignx每一个worker进程都是在epoll或queue事件模型之上,封装成协程。每个请求都有一个协程进行处理。
        2. nignx每个工作进程创建一个lua虚拟机
        3. 工作进程内所有协程共享同一个vm
        4. 每个外部请求由一个lua协程处理,之间数据隔离
        5. lua代码调用io等异步接口时,协程被挂起,上下文数据
        6. 自动保存,不阻塞工作进程
        7. io异步操作完成后还原协程上下文,代码继续执行
      2. nignx lua 挂载点
        1. init_by_lua :系统启动时调用
        2. init_worker_by_lua:worker进程启动时调用
        3. set_by_lua: nignx 变量用复杂lua return
        4. rewrite_by_lua:重写lua规则
        5. access_by_lua : 权限验证阶段
        6. content_by_lua : 内容输出节点
      3. OpenResty由Nignx核心加很多第三方模块组成,默认集成了Lua开发环境,使得nignx可以作为一个web server使用
      4. 静态请求CDN。 DNS用CNAME解析到源站。回源缓存设置。强推失效(Cache Control设置,以及Http中有效性判断)
      5. CDN 自定义缓存策略。可自定义目录过期时间。可自定义后缀名过期时间。可自定义对应权重。可通过界面或者api强制CDN刷新
      6. 静态资源部署策略。
        1. css,js,img等元素使用摘要做文件名部署,新老版本并存且可回滚,资源部署完后再部署html。
        2. 对应静态资源保持生命周期内不会变,max-age可设置的很长,无视失效更新周期
        3. html文件设置no-cache 或较短 max-age,以便于更新
        4. html文件仍然设置较长的max age,依靠动态的获取版本号请求发送到后端,异步下载最新的版本号的html后展示渲染在前端
        5. 动态请求也可以静态化成json资源推送到CDN上
        6. 依靠异步请求获取后端节点对应资源状态做紧急下架处理
        7. 可通过跑批紧急推送cdn内容以使其下架等操作
      7. 全页面静态化 (使用phantonjs应用,编写应轮询生成内容方式,待全静态化页面生成后推送到cdn)
        1. html,css,js 静态资源cdn化
        2. js ajax 动态请求 cdn化
        3. 全页面静态化

下单交易迭代流程

局限

  1. 交易验证完全依赖数据库
  2. 库存行锁

优化

  1. 交易验证部分
    1. 用户校验部分进行缓存。
    2. 活动校验部分:
      1. 引入整体活动发布流程,提前时间发布
      2. 活动部分进行缓存
  2. 库存行锁部分
    • 方案1
      • 业务部分
        1. 活动发布同步库存进缓存
        2. 下单交易减缓存库存
        3. 异步消息扣减数据库内库存
        4. 生成订单
      • 代码部分
        1. 下单后,去缓存中扣减库存
          1. 若无库存,则标记为售罄
          2. 若有库存,则扣减。同时异步发送消息到rocketmq,同时订阅相应topic进行消费,进行数据库扣减
      • 问题点
        1. 异步消息发送失败
        2. 扣减操作执行失败
        3. 下单失败无法正确回补库存
    • 方案2
      • 业务部分
        1. 引入库存操作流水
        2. 引入事务性消息机制
      • 代码部分
        1. 新增库存流水表。
        2. 下单后,发送事务消息到rocketmq。
          1. 当事务成功时,去创建订单,扣减库存。
          2. 当事务回滚时,设置库存流水表状态。
          3. 当事务还未发生时,则通过内部回调方法,进行check,根据库存流水表进行检验
  3. 创建订单前,redis中对对应的商品的设置是否售罄的状态,进行削流。

秒杀流程

局限

  1. 秒杀下单接口会被脚本不停的刷新
  2. 秒杀验证逻辑部分复杂,对交易产生无关联的负载
  3. 存在可能有无限多用户参加秒杀活动

优化

  1. 引入秒杀令牌
    1. 秒杀接口需要依靠令牌才能进入
    2. 秒杀的令牌由秒杀活动模块负责生成
    3. 秒杀活动模块对秒杀令牌生成全权处理
    4. 设置能获得秒杀令牌的用户的数量
    5. 原理
      1. 依靠秒杀令牌的授权原理定制化发牌逻辑,做到大闸功能
      2. 根据秒杀商品初始库存颁发对应数量令牌,控制大闸流量
      3. 用户风控策略钱知道秒杀令牌发放中
      4. 库存售罄判断前置到秒杀令牌发放中
    6. 缺陷
      1. 浪涌流量涌入
      2. 多库存,多商品等令牌限制能力弱
  2. 使用线程池作为拥塞窗口,进行队列泄洪
    1. 原理
      1. 排队有时候比并发更搞笑,如reids的单线程模型
      2. 依靠排队去限制并发流量
      3. 依靠排队和下游拥塞窗口程度调整队列释放流量大小

防刷限流

  1. 加入验证码
  2. 使用限流工具
  3. 根据设备唯一码作为交易凭证,防止黄牛刷单