主要问题:并发读、并发写
关键点
- 高性能
- 一致性
- 高可用
原则
- 请求数据要尽量少
- 减少序列化和反序列化
- 字符转化
- 请求数要尽量少
- 如在请求路径上将多个 Javascript 用逗号合并,服务端一次性返回多个文件
- 路径要尽量短
- 将多个相互强依赖的应用合并部署到一起
- 依赖要尽量少
- 可以把依赖的服务先降级或停用
- 不要有单点
- 将服务无状态化,让实例可以动态伸缩
- 把秒杀系统独立出来单独打造一个系统,并且在系统部署上也独立做一个机器集群,避免影响非秒杀商品的机器
动静分离
- 根据情况把静态数据缓存到离用户近的地方(浏览器、CDN、服务端的 Cache)
- 直接缓存 HTTP 连接
- 怎么做:
- URL 唯一化(如 /id=xxx)
- 分离浏览者相关的因素(比如登录信息,这些通过动态请求获取)
- 分离时间因素,也通过动态请求获取
- 异步化地域因素
- 去掉 Cookie(让缓存的静态数据中不含有 Cookie)
- 服务端:
- 生成完整页面
- 客户端获取动态内容
- 架构方案
- 实体机单机部署:大 Cache 容量,高缓存命中率
- 统一 Cache 层
- 上 CDN:二级 Cache(一级发现没缓存数据就去二级找,都没有就回源获取数据并缓存到一级、二级缓存)
热点数据
- 静态热点数据:能提前预测的
- 通过商业手段(强制让商家登记、对买家每天访问的商品进行大数据计算)
- 动态热点数据:不能提前预测的
- (异步)收集交易链路上各个环节中的中间件产品的热点 Key(Nginx、缓存、RPC 服务框架等)
- 上报热点,透传给下游系统
流量削峰
- 排队
- 答题:延缓请求,并可以防止买家使用秒杀器作弊
- 分层过滤:只在写数据时进行强一致性校验
性能优化
- 影响:
- 减少线程等待时间影响不大
- 减少 CPU 执行时间影响大
- 线程数影响大
- 发现瓶颈:
- 工具:JProfiler、Yourkit
- CPU 使用率超过 95%
- 优化方式:
- 减少编码
- 减少序列化
- Java 极致优化(直接输出流数据、直接使用 Servlet 处理请求)
- 并发读优化
减库存
- 下单减库存:恶意下单
- 付款减库存:超卖
- 预扣库存(最常见):同样可能恶意下单(影响小一些),确保最终一致性
Plan B
- 降级
- 限流:客户端限流、服务端限流
- 拒绝服务