`
飞鱼德蒙
  • 浏览: 13160 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

如何解决微服务架构中的雪崩问题?

阅读更多

记得在三年前公司因为业务发展需要,就曾经将单体应用迁移到分布式框架上来。当时就遇到了这样一个问题:系统仅有一个控制单元,它会调用多个运算单元,如果某个运算单元(作为服务提供者)不可用,将导致控制单元(作为服务调用者)被阻塞,最终导致控制单元崩溃,进而导致整个系统都面临着瘫痪的风险。

那个时候还不知道这其实就是服务的雪崩效应,雪崩效应好比就是蝴蝶效应,说的都是一个小因素的变化,却往往有着无比强大的力量,以至于最后改变整体结构、产生意想不到的结果。雪崩效应也是我们目前研发的产品直面的一道坎,下面我们来看有哪些场景会引发雪崩,又如何避免?对于无法避免的雪崩效应,我们又有哪些应对措施?

1. 星火燎原
1.1农民眼中的微服务

近年来,微服务就象一把燎原的大火,窜了出来并在整个技术社区烧了起来,微服务架构被认为是IT软件服务化架构演进的目标。为什么微服务这么火,微服务能给企业带来什么价值?

1.1.1 以种植农作物的思想来理解微服务

我们以耕种为例来看如何充分利用一块田地的:

  • 先在地里种植了一排排玉米;

  • 后来发现玉米脚下空地可以利用,再间隔一段距离再种上豆角,豆角长大后顺着玉米杆往上爬,最后紧紧地缠绕在玉米杆上;

  • 再后来发现每排玉米之间的空隙地还可以再种些土豆,土豆蔓藤以后会交织在一起,肆虐在玉米脚下吞食营养物质;

表面看来一块土地得到了充分利用,实际上各农作物得不到充分的光照和适宜的营养,如此一来加大了后期除草、松土、施肥、灌溉及收割的成本。

下面的耕植思路是不是更好点呢? 一整块地根据需要分配为若干大小土地块,每块地之间清晰分界,这样就有了玉米地、土豆地、豆角地,再想种什么划块地再耕作就可以了。

这样种植好处很多,比如玉米、豆角和土豆需要的营养物质是不一样的,可由专业技术人员施肥;玉米,豆角和土豆分离,避免豆角藤爬上玉米,缠绕玉米不能自由生长。土豆又汲取玉米需要的营养物质等等问题。

软件系统实现与农作物的种植方式其实也很类似,传统的应用在扩展性,可靠性,维护成本上表现都不尽人意。如何充分利用大量系统资源,管理和监控服务生命周期都是头疼的事情,软件系统设计迫切需要上述的“土地分割种植法”。微服务架构应运而生:在微服务系统中,各个业务系统间通过对消息(字符序列)的处理都非常友好的RestAPI进行消息交互。如此一来,各个业务系统根据Restful架构风格统一成一个有机系统。

1.2 微服务架构下的冰山

泰坦尼克号曾经是世界最大的客轮,在当时被称为是”永不沉没“的,但却在北大西洋撞上冰山而沉没。我们往往只看到它浮出水面的绚丽多彩,水下的基础设施如资源规划、服务注册发现、部署升级,灰度发布等都是需要考虑的因素。

1.2.1 优势
  • 复杂应用分解:复杂的业务场景可被分解为多个业务系统,每个业务系统的每个服务都有一个用消息驱动API定义清楚的边界。

  • 契约驱动:每个业务系统可自由选择技术,组建技术团队利用Mock服务提供者和消费者,并行开发,最终实现依赖解耦。

  • 自由扩展:每个系统可根据业务需要独自进行扩展。

  • 独立部署:每个业务系统互相独立,可根据实际需要部署到合适的硬件机器上。

  • 良好隔离:一个业务系统资源泄漏不会导致整个系统宕掉,容错性较好。

1.2.2 面临的挑战
  • 服务管理:敏捷迭代后的微服务可能越来越多,各个业务系统之间的交互也越来越多,如何做高效集群通信方案也是问题。

  • 应用管理: 每个业务系统部署后对应着一个进程,进程可以启停。如果机器掉电或者宕机了,如何做无缝切换都需要强大的部署管理机制。

  • 负载均衡:为应对大流量场景及提供系统可靠性,同一个业务系统也会做分布式部署即一个业务实例部署在多台机器上。如果某个业务系统挂掉了,如何按需做自动伸缩分布式方案方案也需要考虑。

  • 问题定位:单体应用的日志集中在一起,出现问题定位很方便,而分布式环境的问题定界定位,日志分析都较为困难。

  • 雪崩问题:分布式系统都存在这样一个问题,由于网络的不稳定性,决定了任何一个服务的可用性都不是 100% 的。当网络不稳定的时候,作为服务的提供者,自身可能会被拖死,导致服务调用者阻塞,最终可能引发雪崩效应。

Michael T. Nygard 在精彩的《Release It!》一书中总结了很多提高系统可用性的模式,其中非常重要的两条是:使用超时策略和使用熔断器机制

  • 超时策略:如果一个服务会被系统中的其它部分频繁调用,一个部分的故障可能会导致级联故障。例如,调用服务的操作可以配置为执行超时,如果服务未能在这个时间内响应,将回复一个失败消息。然而,这种策略可能会导致许多并发请求到同一个操作被阻塞,直到超时期限届满。这些阻塞的请求可能会存储关键的系统资源,如内存、线程、数据库连接等。因此,这些资源可能会枯竭,导致需要使用相同的资源系统的故障。在这种情况下,它将是优选的操作立即失败。设置较短的超时可能有助于解决这个问题,但是一个操作请求从发出到收到成功或者失败的消息需要的时间是不确定的。

  • 熔断器模式:熔断器的模式使用断路器来检测故障是否已得到解决,防止请求反复尝试执行一个可能会失败的操作,从而减少等待纠正故障的时间,相对与超时策略更加灵活。

一年一度的双十一已经悄然来临,下面将介绍某购物网站一个Tomcat容器在高并发场景下的雪崩效应来探讨Hystrix的线程池隔离技术和熔断器机制。

2. 从雪崩看应用防护
2.1 雪崩问题的本质:Servlet Container在高并发下崩溃

我们先来看一个分布式系统中常见的简化的模型。Web服务器中的Servlet Container,容器启动时后台初始化一个调度线程,负责处理Http请求,然后每个请求过来调度线程从线程池中取出一个工作者线程来处理该请求,从而实现并发控制的目的。

Servlet Container是我们的容器,如Tomcat。一个用户请求有可能依赖其它多个外部服务。考虑到应用容器的线程数目基本都是固定的(比如Tomcat的线程池默认200),当在高并发的情况下,如果某一外部依赖的服务(第三方系统或者自研系统出现故障)超时阻塞,就有可能使得整个主线程池被占满,增加内存消耗,这是长请求拥塞反模式(一种单次请求时延变长而导致系统性能恶化甚至崩溃的恶化模式)。

更进一步,如果线程池被占满,那么整个服务将不可用,就又可能会重复产生上述问题。因此整个系统就像雪崩一样,最终崩塌掉。

2.2 雪崩效应产生的几种场景
  • 流量激增:比如异常流量、用户重试导致系统负载升高;

  • 缓存刷新:假设A为client端,B为Server端,假设A系统请求都流向B系统,请求超出了B系统的承载能力,就会造成B系统崩溃;

  • 程序有Bug:代码循环调用的逻辑问题,资源未释放引起的内存泄漏等问题;

  • 硬件故障:比如宕机,机房断电,光纤被挖断等。

  • 线程同步等待:系统间经常采用同步服务调用模式,核心服务和非核心服务共用一个线程池和消息队列。如果一个核心业务线程调用非核心线程,这个非核心线程交由第三方系统完成,当第三方系统本身出现问题,导致核心线程阻塞,一直处于等待状态,而进程间的调用是有超时限制的,最终这条线程将断掉,也可能引发雪崩;

2.3 雪崩效应的常见解决方案

针对上述雪崩情景,有很多应对方案,但没有一个万能的模式能够应对所有场景。

  • 针对流量激增,采用自动扩缩容以应对突发流量,或在负载均衡器上安装限流模块。

  • 针对缓存刷新,参考Cache应用中的服务过载案例研究

  • 针对硬件故障,多机房容灾,跨机房路由,异地多活等。

  • 针对同步等待,使用Hystrix做故障隔离,熔断器机制等可以解决依赖服务不可用的问题。

通过实践发现,线程同步等待是最常见引发的雪崩效应的场景,本文将重点介绍使用Hystrix技术解决服务的雪崩问题。后续再分享流量激增和缓存刷新等应对方案。

3. 隔离和熔断

Hystrix 是由Netflix发布,旨在应对复杂分布式系统中的延时和故障容错,基于Apache License 2.0协议的开源的程序库,目前托管在GitHub上。

Hystrix采用了命令模式,客户端需要继承抽象类HystrixCommand并实现其特定方法。为什么使用命令模式呢?使用过RPC框架都应该知道一个远程接口所定义的方法可能不止一个,为了更加细粒度的保护单个方法调用,命令模式就非常适合这种场景。

命令模式的本质就是分离方法调用和方法实现,在这里我们通过将接口方法抽象成HystricCommand的子类,从而获得安全防护能力,并使得的控制力度下沉到方法级别。

Hystrix核心设计理念基于命令模式,命令模式UML如下图:

可见,Command是在Receiver和Invoker之间添加的中间层,Command实现了对Receiver的封装。那么Hystrix的应用场景如何与上图对应呢?

API既可以是Invoker又可以是Reciever,通过继承Hystrix核心类HystrixCommand来封装这些API(例如,远程接口调用,数据库的CRUD操作可能会产生延时),就可以为API提供弹性保护了。

3.1 资源隔离模式

Hystrix之所以能够防止雪崩的本质原因,是其运用了资源隔离模式,我们可以用蓄水池做比喻来解释什么是资源隔离。生活中一个大的蓄水池由一个一个小的池子隔离开来,这样如果某一个水池的水被污染,也不会波及到其它蓄水池,如果只有一个蓄水池,水池被污染,整池水都不可用了。软件资源隔离如出一辙,如果采用资源隔离模式,将对远程服务的调用隔离到一个单独的线程池后,若服务提供者不可用,那么受到影响的只会是这个独立的线程池。

(1)线程池隔离模式:使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)。这个大家都比较熟悉,参考Java自带的ThreadPoolExecutor线程池及队列实现。线程池隔离参考下图:

线程隔离的优点:

  • 请求线程与依赖代码的执行线程可以完全隔离第三方代码;

  • 当一个依赖线程由失败变成可用时,线程池将清理后并立即恢复可用;

  • 线程池可设置大小以控制并发量,线程池饱和后可以拒绝服务,防止依赖问题扩散。

线程隔离的缺点:

  • 增加了处理器的消耗,每个命令的执行涉及到排队(默认使用SynchronousQueue避免排队)和调度;

  • 增加了使用ThreadLocal等依赖线程状态的代码复杂性,需要手动传递和清理线程状态。

对于一些技术这里我找朋友一起录了些视频讲解,如果有兴趣大家可以加群 318261748 免费领取 群里还有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。 

还有更多视频学习资料可以获取,进群请备注领取资料。



 

 

(2)信号量隔离模式:使用一个原子计数器来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃该类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务),参考Java的信号量的用法。

Hystrix默认采用线程池隔离机制,当然用户也可以配置 HystrixCommandProperties为隔离策略为ExecutionIsolationStrategy.SEMAPHORE。

信号隔离的特点:

  • 信号隔离与线程隔离最大不同在于执行依赖代码的线程依然是请求线程,该线程需要通过信号申请;

  • 如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销。

线程池隔离和信号隔离的区别见下图,使用线程池隔离,用户请求了15条线程,10条线程依赖于A线程池,5条线程依赖于B线程池;如果使用信号量隔离,请求到C客户端的信号量若设置了15,那么图中左侧用户请求的10个信号与右边的5个信号量需要与设置阈值进行比较,小于等于阈值则执行,否则直接返回。

建议使用的场景:根据请求服务级别划分不同等级业务线程池,甚至可以将核心业务部署在独立的服务器上。

3.2 熔断器机制

熔断器与家里面的保险丝有些类似,当电流过大时,保险丝自动熔断以保护我们的电器。假设在没有熔断器机制保护下,我们可能会无数次的重试,势必持续加大服务端压力,造成恶性循环;如果直接关闭重试功能,当服务端又可用的时候,我们如何恢复?

熔断器正好适合这种场景:当请求失败比率(失败/总数)达到一定阈值后,熔断器开启,并休眠一段时间,这段休眠期过后熔断器将处与半开状态(half-open),在此状态下将试探性的放过一部分流量(Hystrix只支持single request),如果这部分流量调用成功后,再次将熔断器闭合,否则熔断器继续保持开启并进入下一轮休眠周期。

建议使用场景:Client端直接调用远程的Server端(server端由于某种原因不可用,从client端发出请求到server端超时响应之间占用了系统资源,如内存,数据库连接等)或共享资源。

不建议的场景如下:

  • 应用程序直接访问如内存中的数据,若使用熔断器模式只会增加系统额外开销。

  • 作为业务逻辑的异常处理替代品。

总结思考

本文从自己曾经开发的项目应用的分布式架构引出服务的雪崩效应,进而引出Hystrix(当然了,Hystrix还有很多优秀的特性,如缓存,批量处理请求,主从分担等,本文主要介绍了资源隔离和熔断)。主要分三部分进行说明:

第一部分:以耕种田地的思想引出软件领域设计的微服务架构, 简单的介绍了其优点,着重介绍面临的挑战:雪崩问题。

第二部分:以Tomcat Container在高并发下崩溃为例揭示了雪崩产生的过程,进而总结了几种诱发雪崩的场景及各种场景的应对解决方案,针对同步等待引出了Hystrix框架。

第三部分:介绍了Hystrix背景,资源隔离(总结了线程池和信号量特点)和熔断机制工作过程,并总结各自使用场景。

如Martin Fowler 在其文中所说,尽管微服务架构未来需要经历时间的检验,但我们已经走在了微服务架构转型的道路上,对此我们可以保持谨慎的乐观,这条路依然值得去探索。

 

  • 大小: 31.8 KB
分享到:
评论

相关推荐

    微服务架构设计与实践

    本文档旨在深入探讨微服务架构的设计原理及其在实际项目中的应用。虽然文档中包含了一些难以辨认的符号和字符,但根据上下文和常见微服务架构的概念,我们可以提炼出以下几个核心知识点: 1. **微服务架构的基本...

    SpringCloud微服务架构笔记-共四部分四个PDF文件

    微服务架构是一种将单一应用程序划分为一组小型服务的架构模式,每个服务运行在其独立的进程中,服务之间通过轻量级通信机制(如HTTP/RESTful API)进行交互。这种架构强调服务的独立部署、松耦合和能力自包含,以...

    微服务架构、springcloud介绍PPT

    微服务架构是一种将大型复杂应用程序分解为一组小型、独立、可部署的服务的软件开发方法。每个微服务都专注于特定的功能,具有自己的数据库,并通过轻量级通信机制(通常是API)与其他服务交互。微服务设计原则主要...

    微服务架构解决方案介绍[java培训].docx

    微服务架构是一种现代软件开发的方法论,它将大型的单体应用分解为一系列小型、独立的服务,每个服务专注于执行特定的业务功能。...在实践中,选择适合的微服务架构和工具是关键,以平衡复杂性和效率。

    轻量级微服务架构(下册).pdf

    《轻量级微服务架构(下册)》是关于微服务架构领域的一本深度学习资料,专注于探讨在实际开发环境中如何实现和优化轻量级的微服务架构。这本书结合了Java技术栈,提供了丰富的实践经验和理论知识,对于想要深入了解...

    微服务架构概述视频分享

    在学习和实践Spring Cloud的过程中,你需要理解每个组件的作用和使用方式,掌握如何配置和集成这些组件,以及如何根据实际需求调整微服务架构。微服务架构和Spring Cloud的学习不仅能提升你的技术能力,还能帮助你在...

    SpringCloud微服务分布式架构开发实战-50000-05-作业及参考答案.rar.rar

    除此之外,你还需要掌握Docker和Kubernetes等容器化和编排技术,它们是现代微服务架构中不可或缺的部分,能帮助你快速部署和扩展微服务。SpringCloud Kubernetes项目可以将SpringCloud应用与Kubernetes的原生功能相...

    基于Spring-Cloud的微服务架构.zip

    在现代软件开发中,微服务架构已经成为构建大型、复杂应用的主流模式。Spring-Cloud作为Java生态中的重要工具集,为开发者提供了实现微服务架构的强大支持。本资料将深入探讨如何利用Spring-Cloud构建高效的微服务...

    了解java架构之微服务架构—雪崩效应

    雪崩效应是指在微服务架构中,一旦一个服务不可用,会导致依赖该服务的其他服务也不可用,从而形成一个连锁反应,导致整个服务不可访问。雪崩效应的产生有很多原因,例如程序 bug 导致服务不可用,或者运行缓慢、...

    微服务架构与实践 ,王磊著(1)

    微服务架构是一种现代软件开发的方法论,它提倡将单一应用程序分解为一组小的服务,每个服务都在自己的进程中运行,服务之间通过轻量级的方式(通常是HTTP RESTful API)进行通信。这种方式使得服务可以独立地开发、...

    阿里双十一系统项目实战(缓存架构+高可用服务架构+微服务架构.txt

    ### 阿里双十一系统项目实战(缓存架构+高可用服务架构+微服务架构) #### 缓存架构 在大型互联网系统中,缓存架构是提高系统性能和响应速度的关键技术之一。尤其是在像“双十一”这样的大规模促销活动中,面对...

    微服务架构springboot demo

    本篇将基于"微服务架构springboot demo",深入探讨SpringBoot在微服务架构中的应用。 首先,让我们理解SpringBoot的核心特性。SpringBoot是由Pivotal团队提供的全新框架,旨在简化Spring应用程序的初始搭建以及开发...

    Spring Cloud微服务架构实战[视频课程].txt打包整理.zip

    综上所述,这个压缩包应包含一系列关于Spring Cloud微服务架构的文本资料,可能包括教程、代码示例、问题解答等内容,帮助学习者系统地掌握微服务架构的设计与实施。对于想要深入了解和应用Spring Cloud的人来说,这...

    [云框架]基于SpringCloud的微服务架构-用户指南

    在现代软件开发中,微服务架构已经成为构建可扩展、高可用且易于维护的应用程序的重要模式。Spring Cloud作为Java开发领域内的一个主流微服务框架,为开发者提供了丰富的工具和组件,以帮助实现这一目标。本文将深入...

    SpringBoot微服务架构应用.zip

    在微服务架构中,SpringBoot扮演着至关重要的角色。微服务架构是一种将单一应用程序拆分为一组小型、独立的服务的方法,每个服务都能在其自身的进程中运行,并与轻量级机制(通常是HTTP RESTful API)通信。...

    第六期微服务架构-SpringCloudAlibaba代码和文档.zip

    6. **RocketMQ**:RocketMQ是阿里巴巴开源的分布式消息中间件,它在微服务架构中起到消息队列的作用,实现了异步通信、解耦以及削峰填谷等功能,提高了系统的扩展性和稳定性。 在实际开发过程中,"第六期微服务架构...

    十次方微服务架构前端和后端

    #### 前端在微服务架构中的角色 在微服务架构下,前端通常负责用户界面(UI)的展示和用户体验(UX)的设计。随着前后端分离趋势的发展,前端开发越来越重视数据处理能力和服务端API的有效调用。 1. **API Gateway模式...

    面试专题-面试人员必看-微服务架构面试专题系列:Dubbo+Spring Boot+Spring Cloud.rar

    此外,面试官可能会考察你对微服务架构的理解,包括服务拆分原则、服务治理的重要性以及微服务架构的挑战和解决方案。 总之,理解和掌握Dubbo、Spring Boot和Spring Cloud对于想要在微服务领域发展的IT专业人员来说...

    微服务架构之网关1

    - API网关是微服务架构中的核心组件,它解决了微服务分散带来的流量管理难题。API网关作为一个集中式的入口,对外提供单一接口,隐藏了后端微服务的复杂性。 - API网关的主要职责包括协议转换(如将RPC协议转成...

Global site tag (gtag.js) - Google Analytics