01 秒杀带来的问题和挑战前端
秒杀场景下几大问题:nginx
瞬时流量之高一方面形成的读写冲突,数据库锁会很是严重。redis
应用服务器负载高。spring
秒杀意味着各类活动,须要快速迭代业务,快速上下线,快速支持需求!docker
从系统上讲咱们要作到高可用和高并发;从开发效率上咱们要作到敏捷开发以支持产品快速迭代。数据库
若是把解决秒杀问题当作一种武林秘籍,则产品架构是内功,流量控制是招法,上乘内力搭配制胜招法则无往而不利。编程
02 内功-产品架构解决之道缓存
上图是一个典型的一站式架构,一站式架构存在不少问题。tomcat
首先就是不易扩展,难以维护。服务器
一站式架构中的扩容每每创建在“既然什么都没改,则运行应该正常”的假设之上,而扩容迁移中的各类BUG则隐藏在这种假设之中。
其次是代码难以理解,开发质量得不到保证。随着系统规模的扩大,即使是最初通过良好设计的代码,通过人员迭代,需求压力,也不免会逐渐走向混乱。
最后在一站式架构下项目的可靠性是没法获得保证的,因为业务调整而修改一处逻辑,每每会影响到代码中不少功能的逻辑,而这些额外受到影响的功能则一般不会获得测试,只是在假定这些都是正常的,而这种假定也一般正确,直接潜在的问题爆发。该出错的总会出错,墨菲定律每每这时候是最有效的。
综上能够看出一站式架构设计与敏捷开发格格不入,持续开发,持续集成,持续部署也就只能变成空谈了。
03 微服务架构
上图是优化后的微服务架构,将整个系统拆分红订单、推送、折扣、产品、我的信息等各个微服务,每一个服务都有本身的数据库和缓存等,而且不会互相交叉。各服务之间使用消息队列、RPC调用等传输数据。目前大部分系统设计可能处于一站式架构和微服务架构之间,即上层应用可能已经服务化,可是数据库层面仍是使用同一个库。但我的觉得系统应该朝彻底微服务化努力,隔离数据库层面的共用,以得到更高的系统可靠性。
微服务架构下的系统更加容易进行扩展,能够只针对须要扩容的系统来进行扩容,例如订单量增大,能够只扩容订单服务,而对于其余服务例如我的信息、折扣中心等都都不进行调整,这样一方面减小了系统扩容而对总体稳定性带来的变化,即只需测试新环境中的订单服务便可,随着微服务拆分的越细,这种优点也就越大。
在这种微服务架构下,开发人员能够更加集中精力,将重点放到少许的代码和明确的业务上,这样可以产出更加优雅的代码和良好的设计,在代码优化调整中,也不会因为处处调用而畏手畏脚。每一个微服务能够安排2-3人的小组专门维护,这样也会减小一个微服务内部的沟通成本,而进一步提升生产力。每一个微服务小组能够独立工做,无需过多协调便可实践新功能或想法。
随着技术的不断发展,项目所用的技术架构总会过期,在系统技术革新上,对于传统的一站式架构,甚至是以前提到的服务化架构在应用新技术上都会遇到不小的困难,牵一发动全身,技术改革每每除了推倒重来而没有其余办法。对于微服务架构,因为系统的彻底拆分,公共组件依赖只剩下异步的消息队列,在新技术应用这方面则有了自然优点。微服务基于组件开发设计,提供了在开发过程当中技术选型的最大灵活性,甚至是编程语言的变化均可以进行尝试。
最后要提到的,就是系统稳定性和可用性方面的考虑。在业务需求的持续推进下,持续部署不可避免,在线系统随时都须要进行上线。随着业务的增加、系统的复杂,系统部署时形成问题的潜在可能性会大大提升。而微服务在这方面极大的提升了系统的可靠性。因为微服务的划分,故障自然被隔离,某个服务的故障,不会形成系统的总体瘫痪。而发布的时间因为只须要发布更新相关的服务而大大缩短,这也提升了总体系统的稳定性。当面临问题须要回滚时,也只须要回滚更新相关服务便可,而这在一站式架构中将会是一个灾难。
良好的架构能够更好的支持快速迭代。高内聚的设计将开发人员精力集中到相对集中的领域以设计更优雅的代码实现。随着技术的演进,项目架构也能够跟着一块儿迭代升级。也能够更好的支持持续集成、持续部署。总之,微服务能够渗透到开发中的每一个领域为业务迭代提供更好的支持。微服务这方面建议能够参考spring clound和docker。
04 招法-流量控制解决方案
内功的修炼当然重要,不过并不是一朝一夕可成,是须要长期的努力和不断的沉淀。在武学中当然有高神内力,同时也存在一些致胜招法,一旦练成便可功力猛进,下来就让咱们看一下支持秒杀业务中的一些致胜招法:流量控制解决方案。
05 流量控制解决总览
如上图所示,在项目的整个架构中,流量要作到逐层减小。在每层中均可以使用一些方法来减小流量。
06 前端流量控制
前端流量控制,页面能够设计为动静分离,将尽量多的数据使用CDN进行缓存,以减小到本身服务器上的流量。同时能够加入验证问题,拉长用户下单时间并防止刷单。对较核心逻辑担忧用户破译验证方式,能够再增长服务器端的用户ID访问限制,例如同一用户5s内只能触发1次相关操做等。
07 反向代理流量控制
反向代理(nginx)流量控制,不少页面或者接口响应数据均可以进行静态化处理,应用侧(tomcat)能够定时生成这些资源,发到内容分发服务上,内容分发服务能够将这些静态化资源分发到全部的反向代理上。这些数据能够根据须要按照必定时间间隔进行更新。同时,也能够利用nginx中的缓存配置功能,对热点接口进行缓存。
借助nginx中nginx-lua插件的功能,一些简单逻辑在nginx中直接实现会比较容易,使用恰当,可以大幅减小到应用服务器的请求。例如倒计时,取系统当前时间等逻辑就很是适合在nginx中使用lua实现。对于存在缓存中的商品数量等信息也可由nginx直接访问缓存返回,而不将请求再转发给应用服务器。
08 访问数据分析流量控制
在秒杀中,使人头疼的问题不仅是正常流量突增。因为秒杀活动通常都带有优惠性质,恶意访问也会增多,对于恶意请求在nginx层也能够作不少工做,进行一次拦截。nginx配置中有限制用户访问频率的配置能够根据须要进行配置。同时,也可使用nginx-lua完成一些简单的封禁逻辑,例如调用接口能够封掉指定IP或者UA的访问请求。以后利用日志分析程序,对访问日志进行分析,将须要封掉的IP或者UA等信息调用nginx上提供的接口进行封杀。
09 应用服务器流量控制
通过以前的处理,可以到达应用服务器的流量已经少了不少。对于秒杀活动这类的需求,能够准备专门的活动服务器,专门处理相关逻辑。可使用不一样域名进行分流,或者按照必定URL规则在反向代理服务器上进行分流。同时,对于到数据库进行操做的请求可使用阻塞队减小到数据库的访问以减小行锁等。对于明显超出处理范围的请求能够直接返回秒杀已经结束。例如商品总量300,剩余量100,每台应用服务器上待处理的值超过总量的值则能够直接返回秒杀结束。剩余量能够存入缓存服务中,剩余量能够不那么精确,确保缓存中的剩余量>=实际剩余量便可。超出剩余量的请求也能够直接返回秒杀结束。
缓存存储多点部署以提升系统的总体可用性,避免缓存问题致使系统出错的状况。redis会是一个目前比较好的选择,主从自动切换等功能能够更好的加强系统总体可用性。对于使用单点memcache等系统,建议能够配置keepalived,使得发生机器故障时,IP能够自动转移到另一台健康memacahe服务器上,虽然数据不可恢复,可是缓存组件依然可用。宕机的组件对系统形成的影响每每是不可预料的,尤为是在未良好设计的系统中,总体架构中应任一组件彻底宕机的可能性。
对于秒杀活动需求,多是一系列的活动,相关逻辑能够判断是否能够作到一个专门活动库中,并进行读写分离设计。有条件的状况下,数据库中间件会完成其中一部分工做。在没有相关条件的时候,即便没有数据库中间件,相关逻辑也能够直接在代码中实现。
对于数据库行锁问题,若有须要能够进一步优化,例如上图,将行锁问题经过拆分具体商品,增长分配ID标志,去掉行锁。这个变更的缺点是可能对现有业务逻辑影响较大。不过优势也很明显,在数据库层面消除了行锁。
10 流量控制总结
一图胜千言,以上讨论的流量控制总结方案能够总结到一张图上:
11 总结
结合微服务架构,咱们最终的架构图能够是这样的:
以上供你们参考。
文章来源
做者:胡因可 || 网易乐得技术团队
来自:tech.lede.com/2017/02/17/rd/server/seckill/