秒杀系统
Maven建立工程,管理jar包
jar包依赖
日志、数据库、数据库连接池(生疏点)、DAO相关、Servlet web相关、Spring系列
DAO层的设计
表结构设计、实体类的定义、DAO接口的定义,使用mybatis实现接口,spring实现IOC
1. 秒杀业务分析
<del>展示界面、需要的信息(库存、开始时间、结束时间)、业务逻辑(开始前倒计时、活动期间可以秒杀、结束后显示活动结束)、登陆注册、对高并发场景的处理</del>
库存
减库存、记录购买明细、完整事务、数据落地
购买行为
谁购买成功、购买时间与有效期、付款时间和发货信息
事务的意义
原子性,保证减库存后必然会记录购买明细,否则会发生多卖(记录、没减库存)或少卖的情况(减库存、没记录)
数据落地
mysql vs nosql(高可用、分布式,不支持事务)
2. mysql实现秒杀功能的难点分析
<del>同数据库建立连接比较消耗时间,qps低</del>
并发处理秒杀行为时各个用户之间竞争访问数据库
事务+行级锁
会导致一个用户访问db时别的用户排队等待,变成串行操作,qps低
3.实现哪些秒杀功能
<del>对重复提交的秒杀的处理</del>
秒杀接口的暴露 执行秒杀 相关查询
4.代码开发阶段
- DAO层 设计编码
- Service层 设计编码
- Web层 设计编码
整体梳理
技术栈
日志、数据库、数据库缓存池、Spring、SpringMVC、服务器、Redis
项目结构
DAO层、业务层、WEB层
优化分析
瓶颈点 -- 竞争(数据库的事务、行级锁)
优化思路
流量分流(动静分离、读写分离--redis缓存、接口隐藏减少流量、集群化处理、深度优化--减少行级锁占用时间、使用存储过程)
秒杀页面优化(频繁刷新)
CDN(Content Delivery Network)
静态页面可以放在CDN上,动静分离,分流流量,较少服务器压力
秒杀地址接口优化
为什么秒杀API不能放CDN?
因为CDN放的内容适合放不变化的,秒杀处理会导致数据变化,比如返回值,没开始、活动期间、活动结束的返回值是不同的
适合放在服务端的Redis缓存服务器
- 单机10万QPS,集群可达百万QPS,适合处理高并发场景
- 一致性维护成本低(超时穿透、主动更新)
秒杀操作优化
难点:
无法放CDN
因为最核心的东西不能放CDN,大部分写操作都不会放CDN
后端缓存也比较困难
因为有库存的问题,若命中缓存即返回,可能不会及时更新数据库
一行数据竞争问题
MySQL事务机制、行级锁机制
优化思路:深度优化 比如设计存储过程。减少行级锁占用时间
其他方案分析:
执行秒杀
原子计数器(记录库存,Redis) --》 记录行为(消息队列) --》消费消息并落地(数据库库)
优势:QPS高,性能好
劣势:开发和维护成本很高,幂等性难以保证,技术难点高
MySQL作为解决方案的分析
- 性能低?
一条update记录压力测试(4w QPS),性能其实还不错,但由于事务和行级锁机制,造成竞争,使得后续到达的减库存的更新操作被阻塞,必须等待当前事务被提交或回滚后才能获得锁,进行处理 - 瓶颈分析
update减库存的执行开销+网络延迟和GC开销、insert购买明细的执行开销+网络延迟和GC开销、commit或rollback执行后,后续请求才能获得锁,开始处理。因此会造成竞争和等待
结论:MySQL本身性能还可以,但是Java客户端与数据库之间的通信会造成额外的开销导致性能不尽人意,再一个就是数据库处理请求时产生的竞争问题。
容易疏忽的地方:数据库和Java客户端之间也是依靠网络连接建立的
优化方向:
- 尽快的让事务提交或回滚,减少行级锁的占用时间
- update的处理逻辑由Java客户端转移到MySQL服务器上去执行,避免网络延迟和GC的影响
如何实现2?
- 定制化SQL,修改MySQL源码
- 使用存储过程,使其在数据库服务器上执行而不是在Java客户端执行
优化总结:
前端控制:隐藏秒杀接口、按钮防重复
动静数据分离:CDN、后端缓存
事务竞争优化:减少事务锁的时间
部署
CDN WebServicer Redis MySQL
DAO编码与设计
- 工作内容:
表结构设计、建立数据库和表 - 定义model层:
Entity实体类、DAO接口
配置MyBatis,通过它的xml文件中的mapper实现DAO接口(MyBatis框架可以使我们只管接口,不负责实现) - MyBatis + Spring:
更少编码(可以省略MyBatis API的编写)
更少配置(配置文件扫描:自动扫描路径和包,只写文件名即可定位;DAO实现:MyBatis自动实现DAO接口,自动注入Spring容器)
足够灵活(Mybatis可以定制SQL语句、自由传参、结果集自动赋值。XML提供SQL,另外,DAO接口Mapper)
Spring的使用:
- Spring-DAO.xml:
- (整合MyBatis):
- 配置数据库连接属性文件
- 配置数据库连接池
-配置sqlSessionFactory对象(前两步注入的对象都是用来连接数据库的,第三步注入的对象才是整合MyBatis的)
- (整合MyBatis):