主播:Elaine 今天是白话微服务第一季《服务通信》 番外篇《舱壁与熔断》 舱壁那一集播出后,有朋友问,这不就是熔断嘛。今天就来讲一讲两者的区别。 熔断侧重的是对于单一服务的失败控制。 舱壁侧重的是对多个资源的隔离控制,避免当某类资源的请求超限时的系统影响。 因此,两者的第一个区别是对象的多少,第二个区别是手段的差异。 不严谨的讲,这里的一和二就是舱壁模式,三就是熔断模式。 就技术实现来说,熔断多数是通过失败比率控制的,而隔离则有不同的方案。
本文将深入解析重试、熔断、舱壁、降级四大核心容错策略的触发条件、实现机制与潜在副作用。 **应对策略**:-**动态调整阈值**:根据系统负载动态调整熔断阈值-**分层熔断**:为不同重要性的服务设置不同的熔断策略-**状态同步**:通过广播或配置中心同步熔断状态(需谨慎使用)##3舱壁隔离 :故障隔离的艺术###3.1隔离模式与实现机制舱壁模式将系统资源分隔成独立区间,防止单个服务的故障耗尽所有资源。 :核心服务熔断器持续开启超过5分钟系统整体资源使用率超过90%多个关联服务同时出现异常警告告警(当日处理):单个非核心服务熔断器开启重试率显著上升(超过基线50%)平均响应时间明显恶化总结重试、熔断、舱壁 核心取舍原则:重试是乐观策略,相信故障是暂时的,但需严防重试风暴熔断是保护策略,快速失败以避免资源耗尽,但可能误伤健康请求舱壁是隔离策略,防止故障扩散,但带来资源碎片化开销降级是底线策略,保障核心业务,
我们会结合真实业务案例,引出“舱壁模式”的概念,并通过 Python Demo 展示如何利用线程池做资源隔离,最终构建一个“核心服务不被拉下水”的健壮系统。 我们今天就用通俗的方式讲清楚:雪崩是怎么来的;舱壁模式是怎么帮你挡住“连锁反应”的;怎么用代码简单实现一个防护网。理解雪崩:你以为是个接口慢,结果整个系统炸了什么是“服务雪崩”? 用“舱壁模式”隔离开问题服务舱壁模式是什么?舱壁这个词来自造船:一个船舱进水了不至于整艘船沉没。 有下列特征之一建议隔离:第三方接口不稳定的服务高频调用但非核心业务Q3:是不是所有服务都要做舱壁?不用。越重要的服务,越要把它的依赖服务隔离好。 舱壁模式不是啥高级术语,它本质就是“别把鸡蛋都放一个篮子里”:服务资源单独管理;超时快速失败;按需熔断兜底。就像大楼起火要能“封楼层”,服务挂了也得“就地隔离”。
Resilience4j提供高阶函数(decorators)来增强任何功能接口、lambda表达式或方法引用,包括断路器、速率限制器、重试或舱壁。 下面将会用图例来解释舱壁(Bulkhead)、断路器(CircuitBreaker)、限速器(RateLimiter)、重试(Retry)机制的概念和原理。 舱壁(Bulkhead) Resilience4j提供了两种舱壁模式的实现,可用于限制并发执行的次数: SemaphoreBulkhead(信号量舱壁,默认),基于Java并发库中的Semaphore实现 取决于客户端,以确保正确的线程池大小将与舱壁配置保持一致。 信号量舱壁(SemaphoreBulkhead) ? ? 固定线程池舱壁(FixedThreadPoolBulkhead) ? ?
这些超时值只能通过适当的性能测试/验证SLA等确定 三.Dedicated Thread Pools/Bulkheads 专门的线程池/舱壁模式 另一个重要的设计是:让不同任务请求通过自个专门的线程池请求到各自微服务 这种模式俗称的舱壁。 下图描述了实施舱壁的简单的示例场景:在左侧,微服务A,用同一个连接池去请求X和Y两个服务。如果服务X或服务的Y其中任何一个行为异常,这会影响连接池的整体行为。 如果舱壁模式实现,如该图所示的右侧,即使微服务X被错误操作,只有池X将受到影响。微服务Y可以继续为应用程序提供服务。 ? 这种做法作为一种安全措施,在超时/舱壁,其中一个可能不希望,甚至等待超时所规定的期限上。如果下游系统宕机,对于每个请求来说是没有用的等待时间,而且最后还获得超时异常的响应。 同时也提供了避免这些问题的一些设计,我们讨论了限制、超时、舱壁和断路器模式以及异步集成方法。
2.弹性 弹性工程学的一个关键概念是舱壁。如果系统中的一个组件不可用了,但并没有导致级联故障,那么系统的其他部分还可以正常运行。服务边界就是一个很显然的舱壁。 舱壁模式: 舱壁模式(Bulkhead)隔离了每个工作负载或服务的关键资源,如连接池、内存和CPU。 使用舱壁避免了单个工作负载(或服务)消耗掉所有资源,从而导致其他服务出现故障的场景。 如果舱壁模式实现,如该图所示的右侧,即使微服务X被错误操作,只有池X将受到影响。 微服务Y可以继续为应用程序提供服务. ? 舱壁的概念在软件开发中可以被应用在隔离资源上。 而在工业中使用舱壁将船舶划分为几个部分,以便在船体破坏的情况下,可以将船舶各个部件密封起来。 泰坦尼克号沉没的主要原因之一是其舱壁设计失败,水可以通过上面的甲板倒在舱壁的顶部,最后整个船淹没 ?
通过梳理行业实践,可将防御体系分为三层:边缘白名单过滤、服务内部舱壁隔离,以及业务级兜底降级。 三层防御体系总览防线核心理念典型技术关注点白名单层只让可信流量进来Nginx allow / deny、K8s Gateway AccessControlPolicy请求准入 & 速率约束舱壁层把故障关在小隔间 舱壁模式:在线程池里装上隔水舱原理回顾“Bulkhead” 一词源于船舶隔舱设计,若一个船舱进水,其余舱位仍能浮起船只。 业务处理:舱壁为每条服务流划定并发隔离带,即使单 SKU 库存锁定超时,也不影响支付、推荐等线程。结果输出:若仍发生超时,兜底逻辑在 50 ms 内返回本地缓存或默认文案,维持用户体验。 白名单守住流量大门,舱壁模式为关键线程筑起隔舱,兜底策略在最坏场景保持核心体验。
3.舱壁模式 舱壁(bulkhead),是把自己从故障中隔离开的一种方式。在航运领域,舱壁是船的一部分,合上舱口后可以保护船的其他部分。所以如果船板穿透之后,你可以关闭舱壁门。 在软件架构术语中,有很多不同的舱壁可供我们考虑。 (1)为每个下游服务的连接使用不同的连接池 我们应该为每个下游服务的连接使用不同的连接池。这样的话,如果一个连接池被用尽,其余连接并不受影响。 (2) 应用的拆分 关注点分离也是实现舱壁的一种方式。通过把功能分离成独立的微服务应用,减少了因为一个功能的宕机而影响另一个的可能性。 (3) 使用断路器 我们可以把断路器看作一种密封一个舱壁的自动机制,它不仅保护消费者免受下游服务问题的影响,同时也使下游服务避免更多的调用,以防止可能产生的不利影响。 在很多方面,舱壁是三个模式里最重要的。超时和断路器能够帮助你在资源受限时释放它们,但舱壁可以在第一时间确保它们不成为限制。
Resilience4j提供高阶函数(decorators)来增强任何功能接口、lambda表达式或方法引用,包括断路器、速率限制器、重试或舱壁。 SemaphoreBulkhead(信号量舱壁,默认),基于Java并发库中的Semaphore实现。 FixedThreadPoolBulkhead(固定线程池舱壁),它使用一个有界队列和一个固定线程池。 本文将演示在Spring Boot2中集成Resilience4j库,以及在多并发情况下实现如上两种舱壁模式。 SemaphoreBulkhead的配置项如下: 属性配置 默认值 含义 maxConcurrentCalls 25 舱壁允许的最大并行执行量 maxWaitDuration 0 尝试进入饱和舱壁时,应阻塞线程的最长时间
舱壁(bulkhead)模式 舱壁模式是建立在造船的基础概念上。我们都知道一艘船会被划分为多个水密舱(舱壁),因而即使少数几个部位被击穿漏水,整艘船并不会被淹没。 在舱壁模式中可以隔离每个远程资源,并分配各自的线程池,使之互不影响。 三、spring cloud 中使用 使用 Netflix 的 Hystrix 库来实现上述弹性模式。 4、实现舱壁模式 在基于微服务的应用程序中,通常需要调用多个微服务来完成特定的任务,在不适用舱壁的模式下,这些调用默认是使用同一批线程来执行调用的,而这些线程是为了处理整个 Java 容器的请求而预留的 但是这样很容易出现一个运行缓慢的服务占用全部的线程,所有 hystrix 提供了一种一种易于使用的机制,在不同的远程资源调用间创建‘舱壁’,将不同服务的调用隔离到不同的线程池中,使之互不影响。
逃生舱是一项至关重要的功能,可确保开发人员不会被锁定在特定技术中,尤其是在涉及抽象时。它们提供了一条直接访问和使用底层云服务以及使用现有资源或工具集的途径。 为什么逃生舱对云抽象至关重要 虽然抽象层旨在涵盖常见和基础用例,但它们有目的地构建为避免公开可用的每个配置或设置。逃生舱允许对云服务进行更细粒度的控制,从而实现性能优化和定制。 没有有目的地引入逃生舱的抽象层更难信任和更难使用。然而,许多抽象框架很容易认识到对逃生舱的需求,并预期可以对任何集成进行更改。曾经被烧伤过一两次的工程师可能会发现这些框架更容易信任。 良好逃生舱的示例 了解什么构成了一个好的逃生舱的最佳方法是看一些示例。之前,我提到大多数软件都是建立在抽象层之上的,所以我将从项目中最常见的抽象之一开始:数据库。 Prisma 提供的最重要的逃生舱之一是直接对数据库执行原始 SQL 查询的能力。
什么是 kubectl 从用户的角度来说 kubectl 是 Kubernetes 的驾驶舱,用户可以通过 kubectl 控制 kubernetes 允许的所有操作。
Resilence4J 提供了几个核心模块,按重要程度排序如下: CircuitBreaker 断路 ratelimiter 速率限制 bulkhead 舱壁 retry 自动重试 timelimiter 隔离 BulkHead 一般用于限制对于下游服务的最大并发数量的限制 Resilience4j 提供了两种隔离的实现方式,可以限制并发执行的数量: 实现 SemaphoreBulkhead (信号量舱壁 ) 实现 FixedThreadPoolBulkhead (固定线程池舱壁) SemaphoreBulkhead 信号量舱壁 当信号量存在空闲时,进入系统的请求会直接获取信号量并开始业务处理。 FixedThreadPoolBulkhead 使用一个固定线程池和等待队列来实现舱壁。 当线程池中存在空闲时,此时进入系统的请求将直接进入线程池开启新线程或使用空闲线程来处理请求。 (pom 和信号量舱壁一致无需重复引入) # 采用新线程和主线程脱离时,关闭circuitbreaker的group配置 thread-pool-bulkhead: configs:
舱壁(bulkhead)模式 舱壁模式是建立在造船的基础概念上。我们都知道一艘船会被划分为多个水密舱(舱壁),因而即使少数几个部位被击穿漏水,整艘船并不会被淹没。 在舱壁模式中可以隔离每个远程资源,并分配各自的线程池,使之互不影响。 下图展示了这些模式是如何运用到微服务中的: ? 4、实现舱壁模式 在基于微服务的应用程序中,通常需要调用多个微服务来完成特定的任务,在不适用舱壁的模式下,这些调用默认是使用同一批线程来执行调用的,而这些线程是为了处理整个 Java 容器的请求而预留的 但是这样很容易出现一个运行缓慢的服务占用全部的线程,所有 hystrix 提供了一种一种易于使用的机制,在不同的远程资源调用间创建‘舱壁’,将不同服务的调用隔离到不同的线程池中,使之互不影响。
答:单纯从技术角度也好解决,效仿航天飞机或者潜水艇的密封舱,建一个数据密封舱! 数据密封舱工作原理如下图所示: ? 在私有云中隔离出一个独立内部小网络,作为数据密封舱存在。 运行时遵循以下规则: 3.1 数据密封舱通过Channel 1读取公有云数据时,Channel 2断开。 3.2 从公有云写入数据密封舱的数据在密封舱内经历检验、压缩等初步处理,确认无害后,断开Channel1,通过Channel2向工作私有云写入。 有了这个数据密封舱,就可以保证绝对没有人能够从公有云直接连接到工作私有云,企业内部数据不会被hacker修改。 另外,在数据密封舱对外来数据进行过滤,可以拦截有害信息,如果需要,也可以在此对准备对外发布的数据进行final review。 ?
为了在服务级别上隔离问题,我们可以采用舱壁模式(bulkhead pattern)。你稍后可以在这篇文章中读到更多关于舱壁的信息。 我们还希望我们的组件快速失败,因为我们不想等待坏的实例超时。 *舱壁 Bulkheads 舱壁被用来将一艘船划分成多个部分,这样就可以在船体破裂的情况下对部分封闭。 隔离壁的概念可以应用于软件开发中,做到资源隔离。 泰坦尼克号沉没的主要原因之一,就是它的舱壁有一个设计上的失败,水可以通过舱壁顶部上的甲板注入,淹没整个船体。 泰坦尼克的舱壁(他们没有工作) *断路器 Circuit Breakers 为了限制操作的持续时间,我们可以使用超时。超时可以防止挂起操作并保持系统响应。 架构模式和技术,如缓存、舱壁、限流、熔断,有助于建立可靠的微服务。
Resilience4j提供了两种舱壁模式的实现,可用于限制并发执行的次数: SemaphoreBulkhead(信号量舱壁,默认),基于Java并发库中的Semaphore实现。 SemaphoreBulkhead在各种线程和I / O模型上都能很好地工作,主要原因是它基于信号量,与Hystrix不同,它不提供“影子”线程池选项,它主要取决于客户端,以确保正确的线程池大小将与舱壁配置保持一致 ; FixedThreadPoolBulkhead(固定线程池舱壁),它使用一个有界队列和一个固定线程池。 SemaphoreBulkhead也叫信号量舱壁,当信号量存在剩余时进入系统的请求会直接获取信号量并开始业务处理。 FixedThreadPoolBulkhead使用一个固定线程池和一个等待队列来实现舱壁。当线程池中存在空闲时,则此时进入系统的请求将直接进入线程池开启新线程或使用空闲线程来处理请求。
那就可以直接熔断,不去调用了,这样避免了服务被直接打垮,完全没有恢复的机会RateLimiter(限流器):限制指定时间的请求量,比如订单查询服务,1秒最多1000次,使用的是令牌桶算法Bulkhead(舱壁 ):隔离资源,例如很多付费接口都会设置请求的并发数量,就可以使用信号量舱壁,如果我们调用其他服务希望限制它使用资源,就可以实现线程池模式Retry:很好理解,就是异常的时候可以重试,例如,调用支付服务, BulkheadConfig:信号量舱壁配置类BulkheadRegistry:信号量舱壁注册中心ThreadPoolBulkhead:线程池舱壁ThreadPoolBulkheadConfig:线程池舱壁配置类 ThreadPoolBulkheadRegistry:线程池舱壁注册中心RateLimiterRegistry:限流器注册中心RateLimiterConfig:限流器配置类RateLimiter:限流器 writableStackTraceEnabledtrue当抛出舱壁异常时是否输出完整的堆栈跟踪错误。如果设置为false,则只输出单行的舱壁异常信息。
为了在服务级别上隔离问题,我们可以采用舱壁模式(bulkhead pattern)。你稍后可以在这篇文章中读到更多关于舱壁的信息。 我们还希望我们的组件快速失败,因为我们不想等待坏的实例超时。 *舱壁 Bulkheads 舱壁被用来将一艘船划分成多个部分,这样就可以在船体破裂的情况下对部分封闭。 隔离壁的概念可以应用于软件开发中,做到资源隔离。 泰坦尼克号沉没的主要原因之一,就是它的舱壁有一个设计上的失败,水可以通过舱壁顶部上的甲板注入,淹没整个船体。 泰坦尼克的舱壁(他们没有工作) *断路器 Circuit Breakers 为了限制操作的持续时间,我们可以使用超时。超时可以防止挂起操作并保持系统响应。 架构模式和技术,如缓存、舱壁、限流、熔断,有助于建立可靠的微服务。
Caching) 重试逻辑(Retry Logic) 速率限制器和负载开关(Rate Limiters and Load Shedders) 快速失败(Fail Fast and Independently) 舱壁模式 在服务层面隔离故障,我们可以使用隔板模式(或舱壁模式)(bulkhead pattern)。 此文之后会介绍到隔板模式(或舱壁模式)。 舱壁模式(Bulkheads) 工业中使用舱壁将船舶划分为几个部分,以便在有一部分船体发生破裂,我们就可以将有问题的船体隔离。 舱壁的概念也可以在软件开发中应用于隔离资源。 通过使用舱壁模式,我们可以保护有限的资源不被用尽。 泰坦尼克号沉没的主要原因之一是其舱壁设计失败,水可以通过上面的甲板倒在舱壁的顶部,并将整个船体淹没。