Java生鲜电商平台- 什么是秒杀

通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动

比如说京东秒杀,就是一种定时定量秒杀,在规定的时间内,无论商品是否秒杀完毕,该场次的秒杀活动都会结束。这种秒杀,对时间不是特别严格,只要下手快点,秒中的概率还是比较大的。

淘宝以前就做过一元抢购,一般都是限量 1 件商品,同时价格低到「令人发齿」,这种秒杀一般都在开始时间 1 到 3 秒内就已经抢光了,参与这个秒杀一般都是看运气的,不必太强求

业务特点

瞬时并发量大

秒杀时会有大量用户在同一时间进行抢购,瞬时并发访问量突增 10 倍,甚至 100 倍以上都有。

库存量少

一般秒杀活动商品量很少,这就导致了只有极少量用户能成功购买到。

业务简单

流程比较简单,一般都是下订单、扣库存、支付订单

技术难点

现有业务的冲击

秒杀是营销活动中的一种,如果和其他营销活动应用部署在同一服务器上,肯定会对现有其他活动造成冲击,极端情况下可能导致整个电商系统服务宕机

直接下订单

下单页面是一个正常的 URL 地址,需要控制在秒杀开始前,不能下订单,只能浏览对应活动商品的信息。简单来说,需要 Disable 订单按钮

页面流量突增

秒杀活动开始前后,会有很多用户请求对应商品页面,会造成后台服务器的流量突增,同时对应的网络带宽增加,需要控制商品页面的流量不会对后台服务器、DB、Redis 等组件的造成过大的压力

架构设计思想

限流

由于活动库存量一般都是很少,对应的只有少部分用户才能秒杀成功。所以我们需要限制大部分用户流量,只准少量用户流量进入后端服务器

削峰

秒杀开始的那一瞬间,会有大量用户冲击进来,所以在开始时候会有一个瞬间流量峰值。如何把瞬间的流量峰值变得更平缓,是能否成功设计好秒杀系统的关键因素。实现流量削峰填谷,一般的采用缓存和 MQ 中间件来解决

异步

秒杀其实可以当做高并发系统来处理,在这个时候,可以考虑从业务上做兼容,将同步的业务,设计成异步处理的任务,提高网站的整体可用性

缓存

秒杀系统的瓶颈主要体现在下订单、扣减库存流程中。在这些流程中主要用到 OLTP 的数据库,类似 MySQL、SQLServer、Oracle。由于数据库底层采用 B+ 树的储存结构,对应我们随机写入与读取的效率,相对较低。如果我们把部分业务逻辑迁移到内存的缓存或者 Redis 中,会极大的提高并发效率

整体架构

客户端优化

秒杀页面

秒杀活动开始前,其实就有很多用户访问该页面了。如果这个页面的一些资源,比如 CSS、JS、图片、商品详情等,都访问后端服务器,甚至 DB 的话,服务肯定会出现不可用的情况。所以一般我们会把这个页面整体进行静态化,并将页面静态化之后的页面分发到 CDN 边缘节点上,起到压力分散的作用

防止提前下单

防止提前下单主要是在静态化页面中加入一个 JS 文件引用,该 JS 文件包含活动是否开始的标记以及开始时的动态下单页面的 URL 参数。同时,这个 JS 文件是不会被 CDN 系统缓存的,会一直请求后端服务的,所以这个 JS 文件一定要很小。当活动快开始的时候(比如提前),通过后台接口修改这个 JS 文件使之生效

API 接入层优化

客户端优化,对于不是搞计算机方面的用户还是可以防止住的。但是稍有一定网络基础的用户就起不到作用了,因此服务端也需要加些对应控制,不能信任客户端的任何操作。一般控制分为 2 大类

限制用户维度访问频率

针对同一个用户( Userid 维度),做页面级别缓存,单元时间内的请求,统一走缓存,返回同一个页面

限制商品维度访问频率

大量请求同时间段查询同一个商品时,可以做页面级别缓存,不管下回是谁来访问,只要是这个页面就直接返回

SOA 服务层优化

上面两层只能限制异常用户访问,如果秒杀活动运营的比较好,很多用户都参加了,就会造成系统压力过大甚至宕机,因此需要后端流量控制

对于后端系统的控制可以通过消息队列、异步处理、提高并发等方式解决。对于超过系统水位线的请求,直接采取 「Fail-Fast」原则,拒绝掉

秒杀整体流程图

秒杀系统核心在于层层过滤,逐渐递减瞬时访问压力,减少最终对数据库的冲击。通过上面流程图就会发现压力最大的地方在哪里?

MQ 排队服务,只要 MQ 排队服务顶住,后面下订单与扣减库存的压力都是自己能控制的,根据数据库的压力,可以定制化创建订单消费者的数量,避免出现消费者数据量过多,导致数据库压力过大或者直接宕机。

库存服务专门为秒杀的商品提供库存管理,实现提前锁定库存,避免超卖的现象。同时,通过超时处理任务发现已抢到商品,但未付款的订单,并在规定付款时间后,处理这些订单,将恢复订单商品对应的库存量

Nginx优化

1. 动静分离,不走tomcat获取静态资源

server 

1. gzip压缩,减少静态文件传输的体积,节省带宽,提高渲染速度

gzip 

1. 配置集群负载和容灾,设置失效重连的时间,失效后,定期不会再重试挂掉的节点,参数

· fail_timeout默认为10s

· max_fails默认为1。就是说,只要某个server失效一次,则在接下来的10s内,就不会分发请求到该server上

· proxy_connect_timeout 后端服务器连接的超时时间_发起握手等候响应超时时间

upstream  

1. 集成Varnish做静态资源的缓存

2. 集成tengine做过载的保护

页面优化

1. 降低交互的压力

· 尽量把js、css文件放在少数几个里面,减少浏览器和后端交互获取静态资源的次数

· 尽量避免在秒杀商品页面使用大的图片,或者使用过多的图片

2. 安全控制

· 时间有效性验证:未到秒杀时间不能进行抢单,并且同时程序后端也要做时间有效性验证,因为网页的时间和各自的系统时间决定,而且秒杀器可以通过绕开校验直接调用抢单

· 异步抢单:通过点击按钮刷新抢宝,而不是刷新页面的方式抢宝(答题验证码等等也是ajax交互)

· redis做IP限流

· redis做UserId限流

Redis集群

1. 分布式锁(悲观锁)

2. 缓存热点数据(库存):如果QPS太高的话,另一种方案是通过localcache,分布式状态一致性通过数据库来控制

3. 分布式悲观锁(参考redis悲观锁的代码)

· 悲观锁(因为肯定争抢严重)

· Expire时间(抢到锁后,立刻设置过期时间,防止某个线程的异常停摆,导致整个业务的停摆)

· 定时循环和快速反馈(for缓存有超时设置,每次超时后,重新读取一次库存,还有货再进行第二轮的for循环争夺,实现快速反馈,避免没有货了还在持续抢锁)

1. 异步处理订单

· redis抢锁成功后,记录抢到锁的用户信息后,就可以直接释放锁,并反馈用户,通过异步的方式来处理订单,提升秒杀的效率,降低无意义的线程等待

· 为了避免异步的数据不同步,需要抢到锁的时候,在redis里面缓存用户信息列表,缓存结束后,触发抢单成功用户信息持久化,并且定时的比对一致性

消息队列限流

消息队列削峰限流(RocketMQ自带的Consumer自带线程池和限流措施),集群。一般都是微服务,订单中心、库存中心、积分中心、用户的商品中心

数据库

· 拆分事务提高并发度

· 根据业务需求考虑分库:读写分离、热点隔离拆分,但是会引入分布式事务问题,以及跨库操作的难度
要执行的操作:扣减库存、生成新订单、生成待支付订单、扣减优惠券、积分变动
库存表是数据库并发的瓶颈所在,需要在事务控制上做权衡:可以把扣减库存设置成一个独立的事务,其它操作成一个大的事务(订单、优惠券、积分操作),提高并发度,但是要做好额外的check
update 库存表 set 库存=库存-1 where id=** and 库存>1

· 为了提升并发,需要在事务上做妥协
单机上拆分事务:比如扣减库存表+(生成待支付订单+优惠券扣减+积分变动)是一个大的事务,为了提高并发,可以拆分为2个事务
分库以后引入分布式事务问题,为了保证用户体验,最好还是通过日志分析来人工维护,否则阻塞太严重,并发差

答题验证码

1. 可以防止秒杀器的干扰,让更多用户有机会抢到

2. 延缓请求,每个人的反应时间不同,把瞬间流量分散开来了

3. 验证码的设计可以分为2种

· 验证失败重新刷新答题(12306):服务器交互量大,每错一次交互一次,但是可以大大降低秒杀器答题的可能性,因为没有试错这个功能,答题一直在变
验证失败提示失败,但是不刷新答题的算法:要么答题成功,进入下单界面,要么提示打错,继续答题(不刷新答题,无须交互,用js验证结果)。
这种方案,可以在加载题目的时候一起加载MD5加密的答案,然后后台再校验一遍,实现类似的防止作弊的效果。好处是不需要额外的服务器交互。
MD加密答案的算法里面要引入 userId PK这些因素进来来确保每次答案都不一样而且没有规律,避免秒杀器统计结果集

· 答题的验证:除了验证答案的正确性意外,还要统计反应时间,例如12306的难题,正常人类的答题速度最快是1.5s,那么,小于1s的验证可以判定为机器验证

总结

层层过滤,尽量将请求拦截在上游,降低下游的压力,充分利用缓存与消息队列,提高请求处理速度以及削峰填谷的作用

削峰限流

· 前端+Redis拦截,只有redis扣减成功的请求才能进入到下游

· MQ堆积订单,保护订单处理层的负载,Consumer根据自己的消费能力来取Task,实际上下游的压力就可控了。重点做好路由层和MQ的安全

· 引入答题验证码、请求的随机休眠等措施,削峰填谷

安全保护

· 页面和前端要做判断,防止活动未开始就抢单,防止重复点击按钮连续抢单

· 防止秒杀器恶意抢单,IP限流、UserId限流限购、引入答题干扰答题器,并且对答题器答题时间做常理推断

· 过载丢弃,QPS或者CPU等核心指标超过一定限额时,丢弃请求,避免服务器挂掉,保证大部分用户可用

页面优化,动静分离

· 秒杀商品的网页内容尽可能做的简单:图片小、js css 体积小数量少,内容尽可能的做到动静分离

· 秒杀的抢宝过程中做成异步刷新抢宝,而不需要用户刷新页面来抢,降低服务器交互的压力

· 可以使用Nginx的动静分离,不通过传统web浏览器获取静态资源

· nginx开启gzip压缩,压缩静态资源,减少传输带宽,提升传输速度

· 或者使用Varnish,把静态资源缓存到内存当中,避免静态资源的获取给服务器造成的压力

异步处理

· redis抢单成功后,把后续的业务丢到线程池中异步的处理,提高抢单的响应速度

· 线程池处理时,把任务丢到MQ中,异步的等待各个子系统处理(订单系统、库存系统、支付系统、优惠券系统),异步操作有事务问题,本地事务和分布式事务,但是为了提升并发度,最好牺牲一致性。通过定时扫描统计日志,来发现有问题的订单,并且及时处理

热点分离

尽量的避免秒杀功能给正常功能带来的影响,比如秒杀把服务器某个功能拖垮了
分离可以提升系统的容灾性,但是完全的隔离的改造成本太高了,尽量借助中间件的配置,来实现冷热分离

· 集群节点的分离:nginx配置让秒杀业务走的集群节点和普通业务走的集群不一样。

· MQ的分离:避免秒杀业务把消息队列堆满了,普通业务的交易延迟也特别厉害。

· 数据库的分离:根据实际的秒杀的QPS来选择,热点数据分库以后,增加了分布式事务的问题,以及查询的时候跨库查询性能要差一些(ShardingJDBC有这种功能),所以要权衡以后再决定是否需要分库

避免单点

各个环节都要尽力避免

降级

临时关闭一些没那么重要的功能,比如秒杀商品的转赠功能、红包的提现功能,待秒杀峰值过了,设置开关,再动态开放这些次要的功能。

对标阿里P6+的Java架构师

获取更多学习资料,可以加群:473984645或扫描下方二维码

电商平台 高并发 微服务 方案_Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战...相关推荐

  1. Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战

    Java生鲜电商平台-秒杀系统微服务架构设计与源码解析实战 Java生鲜电商平台-  什么是秒杀 通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动 比如说京东秒杀,就是一种定时定量秒杀,在规定 ...

  2. Java生鲜电商平台-促销系统的架构设计与源码解析

    Java生鲜电商平台-促销系统的架构设计与源码解析 说明:本文重点讲解现在流行的促销方案以及源码解析,让大家对促销,纳新有一个深入的了解与学习过程. 促销系统是电商系统另外一个比较大,也是比较复杂的系 ...

  3. Java生鲜电商平台-电商会员体系系统的架构设计与源码解析

    Java生鲜电商平台-电商会员体系系统的架构设计与源码解析 说明:Java生鲜电商平台中会员体系作为电商平台的基础设施,重要性不容忽视.我去年整理过生鲜电商中的会员系统,但是比较粗,现在做一个最好的整 ...

  4. Java生鲜电商平台-商品中心的架构设计与源码解析(小程序/APP)

    Java生鲜电商平台-商品中心的架构设计与源码解析(小程序/APP) 说明:Java生鲜电商平台中,由于商品的架构很大程度决定了电商的扩展性与伸缩性.对此根据自己多年的生鲜电商经验,整理了以下的商品中 ...

  5. Java生鲜电商平台-商品中心的架构设计与源码解析

    说明:Java生鲜电商平台中,由于商品的架构很大程度决定了电商的扩展性与伸缩性.对此根据自己多年的生鲜电商经验,整理了以下的商品中心思维导图 对于没有接触过生鲜电商的童鞋,可能对基础类目没什么概念.其 ...

  6. Java生鲜电商平台-优惠券系统的架构设计与源码解析

    电商后台:实例解读促销系统 电商后台系统包括商品管理系统.采购系统.仓储系统.订单系统.促销系统.维权系统.财务系统.会员系统.权限系统等,各系统之间相互关联.相互依托,为前端的正常业务流转建立结实稳 ...

  7. 轻量级Rpc框架设计--motan源码解析六:client端服务发现

    一, Client端初始化工作 client端通过RefererConfigBean类实现InitializingBean接口的afterPropertiesSet方法, 进行下面三项检查配置工作: ...

  8. 暴露的全局方法_Dubbo源码解析实战 - 服务暴露原理

    欢迎关注全是干货的技术公众号 dubbo面试中比较喜欢问的两个点:服务发布和服务引用. 人性的拷问 服务发布过程中做了哪些事 dubbo都有哪些协议,他们之间有什么特点,缺省值是什么 什么是本地暴露和 ...

  9. 多线程与高并发(五):强软弱虚四种引用以及ThreadLocal的原理与源码

    上节回顾 AQS(CLH的变种) 因为新加进来的节点要查看前面的节点的状态,所以使用的是双向链表. AQS的底层是 CAS + Volitile,用CAS替代了锁整个链表的操作. 公平锁:上来先排队 ...

最新文章

  1. TensorFlow2-高阶操作
  2. [PAT乙级]1004 成绩排名
  3. 在ionic/cordova中使用百度地图插件
  4. AtomicStampedReference源码分析
  5. python控制树莓派相机_玩转树莓派-Raspberry,控制单反相机进行可编程摄影
  6. day33 UDP、进程
  7. leetcode—16.两数相加链表python解答
  8. 451.根据字符出现频率排序
  9. js混淆还原工具_JavaScript(JS) 压缩 / 混淆 / 格式化 批处理工具
  10. Redis未授权访问缺陷让服务器沦为肉鸡
  11. Centos7中MySQL的安装并设置开机启动
  12. leetcode:6071. 完成所有任务需要的最少轮数【尽可能的多一点3】
  13. CentOS 7.5 安装Nginx教程
  14. 页面各手机屏幕的尺寸
  15. 【jqprint打印】js两种超简单的打印方法
  16. 机器学习之深度学习入门
  17. Ubuntu下最便捷好用微信、QQ(Wine-Tim Wine-QQ )没有之一
  18. TSP问题的解法(java版)
  19. VS用OLE方式对Excel进行读写操作
  20. C语言 学习笔记 存个档而已

热门文章

  1. Python 中的匿名函数,你会用吗
  2. flask那啥 pycharm专业版提供的模板
  3. python opencv 等比例调整(缩放)图片分辨率大小代码 cv2.resize()
  4. 同余(数论) AcWing算法课
  5. c语言指针数组 难点总结,C语言之指针与数组总结
  6. Mybatis常见面试题总结(详细)
  7. c语言不同指令意识,C语言必须理清的概念1
  8. docker 容器安装conposer_Docker下用composer国内镜像安装Laravel
  9. python中的用法_Python中使用@的理解
  10. 关于SVN Server自助修改密码详细教程