目录

  • 1 高并发为什么难做
  • 2 优化方向
  • 3 常见秒杀架构
  • 4 各层次优化细节
  • 5 总结
  • 6 常见问题解答

本文参考58沈剑《架构师之路》,看完思路逐渐清晰,但是文章我也会进行一些补充,我的文章都是遇到一个问题解决一个问题,没有这样总体的思考过.redis,mq这些东西不是为了用而用,而是有一定的方向,要不就会产生一系列问题.

1 高并发为什么难做

例如抢票,票是有限的,库存一份,瞬时流量非常多,都读相同的库存。读写冲突,锁非常严重,这是秒杀业务难的地方。那我们怎么优化高并发业务的架构呢?

2 优化方向

(1)将请求尽量拦截在系统上游

因为数据库历史残留问题,实际上刚开始是并发很少的,因为互联网不断发展,数据库其实并发量并不大.如果一下子打过来,而且还牵扯到锁,请求就会很慢或者超时,基本上体验感会很差.

(2)利用缓存

因为缓存是数据库上面的一层保障,用来抗并发,没有缓存直接打在数据

(3)合理设计缓存队列

高并发缓存队列防止溢出解决方案

(4)动静分离

基于Redis和Nginx实现高并发缓存架构

3 常见秒杀架构

常见的站点架构基本是这样的(绝对不画忽悠类的架构图)

(1)浏览器端最上层,会执行到一些JS代码
(2)站点层,这一层会访问后端数据,拼html页面返回给浏览器
(3)服务层,向上游屏蔽底层数据细节,提供数据访问
(4)数据层,最终的库存是存在这里的,mysql是一个典型(当然还有会缓存)

这个图虽然简单,但能形象的说明大流量高并发的秒杀业务架构,大家要记得这一张图。后面细细解析各个层级怎么优化。

4 各层次优化细节

第一层,客户端怎么优化(浏览器层,APP层)

问大家一个问题,大家都玩过微信的摇一摇抢红包对吧,每次摇一摇,就会往后端发送请求么?回顾我们下单抢票的场景,点击了“查询”按钮之后,系统那个卡呀,进度条涨的慢呀,作为用户,我会不自觉的再去点击“查询”,对么?继续点,继续点,点点点。。。有用么?平白无故的增加了系统负载,一个用户点5次,80%的请求是这么多出来的,怎么整?

(a)产品层面,用户点击“查询”或者“购票”后,按钮置灰,禁止用户重复提交请求;

(b)JS层面,限制用户在x秒之内只能提交一次请求;

APP层面,可以做类似的事情,虽然你疯狂的在摇微信,其实x秒才向后端发起一次请求。这就是所谓的“将请求尽量拦截在系统上游”,越上游越好,浏览器层,APP层就给拦住,这样就能挡住80%+的请求,这种办法只能拦住普通用户(但99%的用户是普通用户)对于群内的高端程序员是拦不住的。firebug一抓包,http长啥样都知道,js是万万拦不住程序员写for循环,调用http接口的,这部分请求怎么处理?

第二层,站点层面的请求拦截

怎么拦截?怎么防止程序员写for循环调用,有去重依据么?ip?cookie-id?…想复杂了,这类业务都需要登录,用uid即可。在站点层面,对uid进行请求计数和去重,甚至不需要统一存储计数,直接站点层内存存储(这样计数会不准,但最简单)。一个uid,5秒只准透过1个请求,这样又能拦住99%的for循环请求。

5s只透过一个请求,其余的请求怎么办?缓存,页面缓存,同一个uid,限制访问频度,做页面缓存,x秒内到达站点层的请求,均返回同一页面。同一个item的查询,例如车次,做页面缓存,x秒内到达站点层的请求,均返回同一页面。如此限流,既能保证用户有良好的用户体验(没有返回404)又能保证系统的健壮性(利用页面缓存,把请求拦截在站点层了)。

页面缓存不一定要保证所有站点返回一致的页面,直接放在每个站点的内存也是可以的。优点是简单,坏处是http请求落到不同的站点,返回的车票数据可能不一样,这是站点层的请求拦截与缓存优化。

好,这个方式拦住了写for循环发http请求的程序员,有些高端程序员(黑客)控制了10w个肉鸡,手里有10w个uid,同时发请求(先不考虑实名制的问题,小米抢手机不需要实名制),这下怎么办,站点层按照uid限流拦不住了。

第三层 服务层来拦截(反正就是不要让请求落到数据库上去)

服务层怎么拦截?大哥,我是服务层,我清楚的知道小米只有1万部手机,我清楚的知道一列火车只有2000张车票,我透10w个请求去数据库有什么意义呢?没错,请求队列!

对于写请求,做请求队列,每次只透有限的写请求去数据层(下订单,支付这样的写业务)

1w部手机,只透1w个下单请求去db

3k张火车票,只透3k个下单请求去db

如果均成功再放下一批,如果库存不够则队列里的写请求全部返回“已售完”。

对于读请求,怎么优化?cache抗,不管是memcached还是redis,单机抗个每秒10w应该都是没什么问题的。如此限流,只有非常少的写请求,和非常少的读缓存mis的请求会透到数据层去,又有99.9%的请求被拦住了。

当然,还有业务规则上的一些优化。回想12306所做的,分时分段售票,原来统一10点卖票,现在8点,8点半,9点,…每隔半个小时放出一批:将流量摊匀。

其次,数据粒度的优化:你去购票,对于余票查询这个业务,票剩了58张,还是26张,你真的关注么,其实我们只关心有票和无票?流量大的时候,做一个粗粒度的“有票”“无票”缓存即可。

第三,一些业务逻辑的异步:例如下单业务与 支付业务的分离。这些优化都是结合 业务 来的,我之前分享过一个观点“一切脱离业务的架构设计都是耍流氓”架构的优化也要针对业务。

第四层 最后是数据库层

浏览器拦截了80%,站点层拦截了99.9%并做了页面缓存,服务层又做了写请求队列与数据缓存,每次透到数据库层的请求都是可控的。db基本就没什么压力了,闲庭信步,单机也能扛得住,还是那句话,库存是有限的,小米的产能有限,透这么多请求来数据库没有意义。

全部透到数据库,100w个下单,0个成功,请求有效率0%。透3k个到数据,全部成功,请求有效率100%。

5 总结

上文应该描述的非常清楚了,没什么总结了,对于秒杀系统,再次重复下我个人经验的两个架构优化思路:
(1)尽量将请求拦截在系统上游(越上游越好);

(2)读多写少的常用多使用缓存(缓存抗读压力);

浏览器和APP:做限速

站点层:按照uid做限速,做页面缓存

服务层:按照业务做写请求队列控制流量,做数据缓存

数据层:闲庭信步

并且:结合业务做优化

6 常见问题解答

问题1、按你的架构,其实压力最大的反而是站点层,假设真实有效的请求数有1000万,不太可能限制请求连接数吧,那么这部分的压力怎么处理?

答:每秒钟的并发可能没有1kw,假设有1kw,解决方案2个:

(1)站点层是可以通过加机器扩容的,最不济1k台机器来呗。
(2)如果机器不够,抛弃请求,抛弃50%(50%直接返回稍后再试),原则是要保护系统,不能让所有用户都失败。

问题2、“控制了10w个肉鸡,手里有10w个uid,同时发请求” 这个问题怎么解决哈?

答:上面说了,服务层写请求队列控制

问题3:限制访问频次的缓存,是否也可以用于搜索?例如A用户搜索了“手机”,B用户搜索“手机”,优先使用A搜索后生成的缓存页面?

答:这个是可以的,这个方法也经常用在“动态”运营活动页,例如短时间推送4kw用户app-push运营活动,做页面缓存。

问题4:如果队列处理失败,如何处理?肉鸡把队列被撑爆了怎么办?

答:处理失败返回下单失败,让用户再试。队列成本很低,爆了很难吧。最坏的情况下,缓存了若干请求之后,后续请求都直接返回“无票”(队列里已经有100w请求了,都等着,再接受请求也没有意义了)

问题5:站点层过滤的话,是把uid请求数单独保存到各个站点的内存中么?如果是这样的话,怎么处理多台服务器集群经过负载均衡器将相同用户的响应分布到不同服务器的情况呢?还是说将站点层的过滤放到负载均衡前?

答:可以放在内存,这样的话看似一台服务器限制了5s一个请求,全局来说(假设有10台机器),其实是限制了5s 10个请求,解决办法:

1)加大限制(这是建议的方案,最简单)
2)在nginx层做7层均衡,让一个uid的请求尽量落到同一个机器上

问题6:服务层过滤的话,队列是服务层统一的一个队列?还是每个提供服务的服务器各一个队列?如果是统一的一个队列的话,需不需要在各个服务器提交的请求入队列前进行锁控制?

答:可以不用统一一个队列,这样的话每个服务透过更少量的请求(总票数/服务个数),这样简单。统一一个队列又复杂了。

问题7:秒杀之后的支付完成,以及未支付取消占位,如何对剩余库存做及时的控制更新?

答:数据库里一个状态,未支付。如果超过时间,例如45分钟,库存会重新会恢复(大家熟知的“回仓”),给我们抢票的启示是,开动秒杀后,45分钟之后再试试看,说不定又有票哟~

问题8:不同的用户浏览同一个商品 落在不同的缓存实例显示的库存完全不一样 请问老师怎么做缓存数据一致或者是允许脏读?

答:目前的架构设计,请求落到不同的站点上,数据可能不一致(页面缓存不一样),这个业务场景能接受。但数据库层面真实数据是没问题的。

问题9:就算处于业务把优化考虑“3k张火车票,只透3k个下单请求去db”那这3K个订单就不会发生拥堵了吗?

答:(1)数据库抗3k个写请求还是ok的;(2)可以数据拆分;(3)如果3k扛不住,服务层可以控制透过去的并发数量,根据压测情况来吧,3k只是举例;

问题10;如果在站点层或者服务层处理后台失败的话,需不需要考虑对这批处理失败的请求做重放?还是就直接丢弃?

答:别重放了,返回用户查询失败或者下单失败吧,架构设计原则之一是“fail fast”。

问题11.对于大型系统的秒杀,比如12306,同时进行的秒杀活动很多,如何分流?

答:垂直拆分

问题12、额外又想到一个问题。这套流程做成同步还是异步的?如果是同步的话,应该还存在会有响应反馈慢的情况。但如果是异步的话,如何控制能够将响应结果返回正确的请求方?

答:用户层面肯定是同步的(用户的http请求是夯住的),服务层面可以同步可以异步。

问题13、秒杀群提问:减库存是在那个阶段减呢?如果是下单锁库存的话,大量恶意用户下单锁库存而不支付如何处理呢?

答:数据库层面写请求量很低,还好,下单不支付,等时间过完再“回仓”,之前提过了。

高并发秒杀系统优化思路相关推荐

  1. 微服务高并发秒杀系统

    微服务高并发秒杀系统 在做完乐优商城项目之后发现缺少秒杀未编写,打算上手实现一下这个基本电商都需要的功能,参考https://blog.csdn.net/lyj2018gyq/article/deta ...

  2. Java高并发秒杀Api-业务分析与DAO层构建1

    章节目录 1.为什么使用Spring+Spring MVC+Mybatis 2.秒杀业务特性 3.秒杀分析过程.优化思路 4.相关技术介绍 5.基于Maven创建项目 6.秒杀业务分析 7.秒杀事务的 ...

  3. SpringBoot实现Java高并发秒杀系统之Service层开发(二)

    继上一篇文章:SpringBoot实现Java高并发秒杀系统之DAO层开发 我们创建了SpringBoot项目并熟悉了秒杀系统的表设计,下面我们将讲解一下秒杀系统的核心部分:Service业务层的开发 ...

  4. Java高并发秒杀系统【观后总结】

    项目简介 在慕课网上发现了一个JavaWeb项目,内容讲的是高并发秒杀,觉得挺有意思的,就进去学习了一番. 记录在该项目 我结合其资料和观看视频的时候整理出从该项目学到了什么... 项目Dao层 日志 ...

  5. Java高并发秒杀平台(Redis + RabbitMQ)

    Seconds-Kill 本项目是一个模拟高并发环境下基于 SpringBoot 的秒杀购物平台.为了减少对数据库的直接访问,通过 Redis 实现了缓存优化:并通过 RabbitMQ 消息中间件来接 ...

  6. Java高并发秒杀API(四)之高并发优化

    Java高并发秒杀API(四)之高并发优化 1. 高并发优化分析 关于并发 并发性上不去是因为当多个线程同时访问一行数据时,产生了事务,因此产生写锁,每当一个获取了事务的线程把锁释放,另一个排队线程才 ...

  7. 实战:基于 RocketMQ 的电商高并发秒杀场景

    内容简介: "秒杀"这一业务场景在如今已经不是什么新鲜名词,它本质上属于短时突发性高并发访问问题,业务特点如下: 定时触发,流量在瞬间突增: 秒杀请求中常常只有部分能够成功: 秒杀 ...

  8. 当Golang遇到高并发秒杀

    遇到go也是工作上的调整,工作上做架构相关的事情,对新发展比较火爆的语言肯定要关注下.就这样步入了GO语言的世界,GO给我带来了全新的体验: 一直做一件事情的人往往会被一件事情所困,开始实践GO语言的 ...

  9. 实战分布式之电商高并发秒杀场景总览

    前言 本文是新系列"实战高并发"的开篇作.这个系列作为"我说分布式"的子系列,将着重挑选若干典型的分布式实战场景,尽量对当下高并发领域较为热门的架构及业务场景做 ...

最新文章

  1. C++内存管理与内存泄漏及其检测
  2. 【AI不惑境】深度学习中的多尺度模型设计
  3. 【学习笔记】Python - tkinter
  4. echars水状_Echarts饼状图属性设置
  5. vs2013创建及使用DLL
  6. C# static readonly 与 const 的区别
  7. python 一个简单的天气预报程序
  8. 基于PHPExcel的常用方法总结
  9. 支持向量机(Support Vector Machine,SVM)
  10. 2007最新最强杀毒软件破解大全
  11. ONVIF系列——海康摄像头设置onvif协议开启
  12. Linux驱动子系统之I2C(一)
  13. chrome 本地文件 翻译工具
  14. RN cannot add a child that doesnot have a YogoNode to a parent without a measure function!
  15. 申请提前转正,当天就被开除了
  16. Fortran文件操作-open
  17. 阿里巴巴Java开发手册摘要(一)
  18. [黑苹果]黑苹果折腾记 -- 安装10.12.6 macOS Sierra
  19. VS2017编译WRL的Callback模版函数兼容性问题及解决方法
  20. IObit Uninstaller 8.0中文专业版-软件卸载神器(内含注册码)

热门文章

  1. SQL 插入数据和查询
  2. 零基础编程——块语言编程游戏攻略之捉虫篇
  3. ICESat-1/GLAS14卫星数据处理1(附代码)-冰川物质平衡监测
  4. VC工具栏图标制作流程
  5. 【ECharts】echarts数据化图表入门级教程(附10个案例)
  6. 宝藏世界中什么叫服务器中断了,宝藏世界版本检查错误解决方法 Trove登陆不了怎么办...
  7. 深入探索Java反射机制:解析原理与应用
  8. 使用百度api获取经纬度的偏差问题
  9. 利用matlab调用cplex求解器时遇到猫图是什么原因呢
  10. VSCode主题颜色的更改,让字体变暗一些,不那么刺眼(类IDEA风)