高并发场景
最近在慕课网上发现了一个高并发秒杀系统课程,学习了一下,对最后一章节里的场景分析和优化学习过程做了一个记录,分享一下,感觉这个老师讲的挺好的。
以一个秒杀场景为例,秒杀功能包括:
秒杀接口暴露(不到秒杀时间不允许用户访问)
执行秒杀
相关查询
高并发具体业务(秒杀)场景流程
红色部分可能会发生并发操作,绿色部分不会有并发操作
下面具体分析并发场景各个节点的优化
1.详情页
解决方案
- 提供一个CDN节点,把静态资源(html ,JavaScript等)存储上去,实际上在并发操作过来的时候,用户访问的不再是服务器系统上的资源,而是CDN上的资源,这就避免了对服务器造成压力
- 拿系统时间还是需要去服务器秒杀系统上拿
什么是CDN?
- CDN 内容分发网络,加速用户获取数据的系统
- 部署在离用户最近的网络节点上(通过运营商接口访问城域网最近的节点)
- 命中CDN就不需要访问后端服务器了,大互联网公司都有自己的CDN集群,或者租用CDN集群
2.为什么访问内存时间不用优化?
访问一次内存只需要10ns,很快
3.秒杀地址接口优化
难点
- 无法使用CDN缓存(只在一定时间内有效)
- 适合存在服务器端中的redis中,可以抗很高的QPS(十万百万级)且一致性维护成本低
解决方案
这里要注意双写一致性问题
-
双写一致性问题
-
主流方法基本上都采用第二或第三种,或者用以下解决方案
-
解决方案
- 将数据库缓存更新和读取操作进行串行化
- 项目里维护一组线程池和内存队列
- 更新数据时,根据数据唯一标志将请求路由到一个jvm队列中,然后更新,请求结束
- 读数据时,先查缓存,数据不存在,根据唯一标志路由,发送到同一jvm队列中,重新读取后更新缓存
- 由于都在同一队列中,执行顺序具有先后性
4.秒杀操作优化
难点
- 无法使用CDN缓存
- 后端缓存困难:库存问题(不同用户访问redis同时命中,会产生不一致)
- 一行数据竞争:热点商品
解决方案
方案一
- 原子计数器:redis实现,记录商品的库存,减库存操作保证原子性
- 记录行为消息:谁减了库存?生产此条消息放入分布式消息队列中
- 消费消息并落地:消费消息记录到MySQL数据库中
痛点
运维成本太高,都依赖于分布式的NoSQL和MQ
开发成本太高,数据一致性不好保证,回滚方案设计复杂
扫描二维码关注公众号,回复:
11209555 查看本文章
幂等性难保证,重复秒杀问题
为什么不能直接用MySQL?
因为低效率
一条update压力测试结果: 4W QPS,一秒种商品可以更新4W次,那为什么效率还低?
- update insert 等操作会有网络延迟和GC操作(由于Java的特性)
- 事务阻塞十分严重
优化方向:
减少行级锁持有时间
把客户端逻辑放到MySQL服务端,避免网络延迟和GC影响(比如判断是否更新成功)
总结
附上慕课网课程地址:
https://www.imooc.com/learn/632