构建秒杀相关内容。项目包含三个模块:
- 注册登录。
- 商品详情模块。
- 下单交易模块.
- 限流削峰模块
- 秒杀模块
- 优化tomcat
- spring-configuration-metadata.json文件下,有tomcat相关配置,可修改相关配置增加tomcat的并发量
- spring-tomcat-accept-count:默认长度为100 等待队列长度
- spring-tomcat-max-connection:最大可连接数,默认为10000
- spring.tomcat.max-threads:最大工作线程数。默认200
- spring.tomcat.min-spare-threads:最小工作线程数,默认为10
- 自定义WebServerConfiguration
- 目前局限:
- 不能过分提高进程调度线程数。因为提高的越多,就会花费很多时间在CPU调度上。
- 目前局限:等待队列长度不能无限长,消耗内存,出队入库也耗内存。
- spring-configuration-metadata.json文件下,有tomcat相关配置,可修改相关配置增加tomcat的并发量
- 水平扩展。增加nginx,
- web服务器
- 实现横向扩容 => 静态资源配置nginx服务器上,通过指定路径访问(如注册页面,商品详情页面)
- 反向代理服务器
- 设置upstream server
- 设置动态请求为proxy pass 路径
- 动静分离服务器
- 静态资源直接访问nignx
- 动态资源直接访问nignx代理的服务器
- nignx 高性能原因
- epoll机制。变更触发回调直接读取。理论无上限。
- master-worker机制。master进程管理worker进程
- 协程机制。依附于线程的内存模型,切换开销小。遇到阻塞归还执行权,代码同步,无需加锁。
- web服务器
- 使用redis 实现分布式会话,前期使用tomcat容器的session,后期考虑app,小程序等使用token
- 缓存
- Redis缓存。单机版。sentinal哨兵模式。集群cluster模式。
- 热点本地缓存Guava。可控制大小和超时。可配置lru策略。线程安全。
- 使用nginx 增加 lua缓存(借用lua的协程机制)=》 openrestry 配合redis 进行网络缓存 =》 引入静态资源CDN =》全局静态资源CDN。
- nignx协程。
- nignx每一个worker进程都是在epoll或queue事件模型之上,封装成协程。每个请求都有一个协程进行处理。
- nignx每个工作进程创建一个lua虚拟机
- 工作进程内所有协程共享同一个vm
- 每个外部请求由一个lua协程处理,之间数据隔离
- lua代码调用io等异步接口时,协程被挂起,上下文数据
- 自动保存,不阻塞工作进程
- io异步操作完成后还原协程上下文,代码继续执行
- nignx lua 挂载点
- init_by_lua :系统启动时调用
- init_worker_by_lua:worker进程启动时调用
- set_by_lua: nignx 变量用复杂lua return
- rewrite_by_lua:重写lua规则
- access_by_lua : 权限验证阶段
- content_by_lua : 内容输出节点
- OpenResty由Nignx核心加很多第三方模块组成,默认集成了Lua开发环境,使得nignx可以作为一个web server使用
- 静态请求CDN。 DNS用CNAME解析到源站。回源缓存设置。强推失效(Cache Control设置,以及Http中有效性判断)
- CDN 自定义缓存策略。可自定义目录过期时间。可自定义后缀名过期时间。可自定义对应权重。可通过界面或者api强制CDN刷新
- 静态资源部署策略。
- css,js,img等元素使用摘要做文件名部署,新老版本并存且可回滚,资源部署完后再部署html。
- 对应静态资源保持生命周期内不会变,max-age可设置的很长,无视失效更新周期
- html文件设置no-cache 或较短 max-age,以便于更新
- html文件仍然设置较长的max age,依靠动态的获取版本号请求发送到后端,异步下载最新的版本号的html后展示渲染在前端
- 动态请求也可以静态化成json资源推送到CDN上
- 依靠异步请求获取后端节点对应资源状态做紧急下架处理
- 可通过跑批紧急推送cdn内容以使其下架等操作
- 全页面静态化 (使用phantonjs应用,编写应轮询生成内容方式,待全静态化页面生成后推送到cdn)
- html,css,js 静态资源cdn化
- js ajax 动态请求 cdn化
- 全页面静态化
- nignx协程。
- 交易验证完全依赖数据库
- 库存行锁
- 交易验证部分
- 用户校验部分进行缓存。
- 活动校验部分:
- 引入整体活动发布流程,提前时间发布
- 活动部分进行缓存
- 库存行锁部分
- 方案1
- 业务部分
- 活动发布同步库存进缓存
- 下单交易减缓存库存
- 异步消息扣减数据库内库存
- 生成订单
- 代码部分
- 下单后,去缓存中扣减库存
- 若无库存,则标记为售罄
- 若有库存,则扣减。同时异步发送消息到rocketmq,同时订阅相应topic进行消费,进行数据库扣减
- 下单后,去缓存中扣减库存
- 问题点
- 异步消息发送失败
- 扣减操作执行失败
- 下单失败无法正确回补库存
- 业务部分
- 方案2
- 业务部分
- 引入库存操作流水
- 引入事务性消息机制
- 代码部分
- 新增库存流水表。
- 下单后,发送事务消息到rocketmq。
- 当事务成功时,去创建订单,扣减库存。
- 当事务回滚时,设置库存流水表状态。
- 当事务还未发生时,则通过内部回调方法,进行check,根据库存流水表进行检验
- 业务部分
- 方案1
- 创建订单前,redis中对对应的商品的设置是否售罄的状态,进行削流。
- 秒杀下单接口会被脚本不停的刷新
- 秒杀验证逻辑部分复杂,对交易产生无关联的负载
- 存在可能有无限多用户参加秒杀活动
- 引入秒杀令牌
- 秒杀接口需要依靠令牌才能进入
- 秒杀的令牌由秒杀活动模块负责生成
- 秒杀活动模块对秒杀令牌生成全权处理
- 设置能获得秒杀令牌的用户的数量
- 原理
- 依靠秒杀令牌的授权原理定制化发牌逻辑,做到大闸功能
- 根据秒杀商品初始库存颁发对应数量令牌,控制大闸流量
- 用户风控策略钱知道秒杀令牌发放中
- 库存售罄判断前置到秒杀令牌发放中
- 缺陷
- 浪涌流量涌入
- 多库存,多商品等令牌限制能力弱
- 使用线程池作为拥塞窗口,进行队列泄洪
- 原理
- 排队有时候比并发更搞笑,如reids的单线程模型
- 依靠排队去限制并发流量
- 依靠排队和下游拥塞窗口程度调整队列释放流量大小
- 原理
- 加入验证码
- 使用限流工具
- 根据设备唯一码作为交易凭证,防止黄牛刷单