Spring Boot 中为什么 需要限流、降级和熔断?

为什么 Spring Boot 需要限流、降级和熔断?

在一个分布式系统,特别是使用 Spring Boot 微服务构建的系统中,应用程序很可能面临各种与流量、依赖故障和资源限制相关的挑战。如果没有适当的保护措施,这些挑战可能导致:

  1. 系统过载和级联故障:

    • 问题: 突发的流量激增(无论是合法的还是恶意的),或者性能不佳的上游服务,都可能使你的应用程序不堪重负。如果一个服务变得缓慢或无响应,可能会导致线程堆积,消耗资源(如 CPU、内存、数据库连接),并最终导致应用程序崩溃。
    • 级联效应: 在微服务架构中,服务通常相互依赖。如果一个服务因过载而发生故障,可能会触发依赖于它的其他服务的故障,从而在整个系统中产生多米诺骨牌效应。这就是所谓的级联故障。
  2. 资源耗尽:

    • 问题: 不受控制的流量或低效的代码可能导致关键资源迅速耗尽,例如:
      • 线程池: 过多的并发请求会耗尽可用的线程,导致请求排队和响应时间缓慢。
      • 数据库连接: 过多的请求会耗尽数据库连接池,导致数据库性能下降和潜在的故障。
      • 内存: 处理大量请求或处理低效操作可能会导致内存泄漏或过度内存使用,从而导致 OutOfMemoryError 错误。
      • CPU: 高请求率和复杂的处理会使 CPU 资源饱和,导致应用程序无响应。
    • 后果: 资源耗尽会导致性能下降、应用程序不稳定以及潜在的服务中断。
  3. 依赖故障:

    • 问题: 微服务架构依赖于与其他服务(数据库、外部 API、其他微服务)的通信。这些依赖关系可能会因网络问题、服务中断或依赖服务自身的性能问题而失败。
    • 影响: 如果你的应用程序不能优雅地处理依赖故障,它可能会被阻塞,等待无响应的服务,导致响应缓慢以及自身服务内的资源耗尽。这再次导致级联故障。
  4. 缓慢或不稳定的上游服务:

    • 问题: 即使依赖项没有完全失败,也可能在高负载或由于自身内部问题而变得缓慢或不稳定。
    • 影响: 你的应用程序,等待来自上游服务的缓慢响应,也会变得缓慢且无响应。这会降低用户体验,并且仍然可能导致资源耗尽,因为请求会排队等待响应。

为了减轻这些风险并构建弹性的应用程序,我们采用了限流、降级和熔断等保护机制。 这些机制不是相互排斥的,而是互补的策略,共同保护你的 Spring Boot 应用程序。

1. 限流(流量整形/节流) (Rate Limiting)

  • 定义: 限流控制允许请求进入你的应用程序或特定服务的速率。它设置在给定时间窗口内可以处理的最大请求数量(例如,每秒请求数、每分钟请求数)。

  • 目的:

    • 防止过载: 限流的主要目标是防止你的应用程序被过度的流量压垮。通过限制传入的请求速率,你可以确保你的系统在其容量范围内运行并保持响应能力。
    • 保护上游服务: 如果你的服务调用下游服务,限流还可以通过防止你的服务发送过多的请求并可能使它们过载来保护这些下游服务。
    • 公平资源分配: 限流可用于确保对资源的公平访问,尤其是在多租户系统中。你可以为不同的用户或客户端分配不同的请求配额。
    • 缓解拒绝服务 (DoS) 攻击: 限流可以通过限制来自单个来源或所有来源的请求数量来有效降低 DoS 攻击的影响,从而防止攻击者使你的系统不堪重负。
  • 常用限流算法:

    • 令牌桶 (Token Bucket): 一个桶装有令牌,只有在令牌可用时才能处理请求。令牌以恒定的速率添加到桶中。这是一种常见且灵活的算法,允许突发流量达到桶的容量。
    • 漏桶 (Leaky Bucket): 请求进入一个桶,然后以恒定的速率从桶中处理(泄漏)请求。这可以平滑流量并防止突发。
    • 固定窗口计数器 (Fixed Window Counter): 在固定的时间窗口(例如,1 分钟)内计数请求。一旦窗口过期,计数器就会重置。实现简单,但在窗口边界可能存在“突发”问题。
    • 滑动窗口计数器 (Sliding Window Counter): 类似于固定窗口,但窗口随时间滑动,提供更平滑的限流效果,并避免固定窗口的突发问题。
  • Spring Boot 实现选项:

    • Guava RateLimiter Google Guava 库提供了基于令牌桶算法的简单 RateLimiter。你可以轻松地将其集成到你的 Spring Boot 控制器或服务中。
    • Spring Cloud Gateway Rate Limiter: 如果你正在使用 Spring Cloud Gateway 作为你的 API 网关,它提供了内置的限流功能,使用不同的算法(例如,基于 Redis 的令牌桶,每秒请求数)。
    • Sentinel: 阿里巴巴开源的 Sentinel 是一个强大的流量控制、熔断降级组件。它提供了全面的限流功能,包括各种算法和动态配置。
    • Resilience4j: 虽然主要以熔断和弹性模式而闻名,但 Resilience4j 也提供了限流功能。
    • 自定义拦截器/过滤器: 你可以创建自定义 Spring 拦截器或过滤器来实现你自己的限流逻辑,特别是当你有特定需求或想要与外部限流服务集成时。
    • Redis/Memcached: 你可以使用 Redis 或 Memcached 作为分布式计数器,并使用脚本或客户端逻辑实现限流逻辑。
  • 示例( Guava RateLimiter):

    import com.google.common.util.concurrent.RateLimiter;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;@RestController
    public class MyController {private final RateLimiter rateLimiter = RateLimiter.create(10.0); // 每秒允许 10 个请求@GetMapping("/api/resource")public String accessResource() {if (rateLimiter.tryAcquire()) { // 尝试获取令牌// 如果获取到令牌,则处理请求return "资源访问成功";} else {// 达到限流阈值return "超出限流阈值。请稍后重试。";}}
    }
    

2. 降级(回退/回退机制) (Degradation)

  • 定义: 降级,也称为回退,是一种策略,当系统资源紧张或依赖服务出现故障时,为了保证核心服务的可用性,提供降低的或替代的功能。 系统不会完全失败,而是优雅地降低其功能。

  • 目的:

    • 保持核心功能: 降级确保即使系统的某些部分发生故障,核心、最关键的功能仍然可以运行。 你优先考虑基本功能,而不是不太重要的功能。
    • 改善中断期间的用户体验: 降级可以为用户提供降级但仍然可用的体验,而不是显示错误页面或完全失败。 这比完全服务中断要好得多。
    • 防止级联故障: 通过提供回退机制,你可以防止一个服务中的故障传播到依赖于它的其他服务。
    • 资源节约: 在高负载或依赖故障期间,降级可以通过减少故障组件上的负载并将资源集中在基本服务上来帮助节约资源。
  • 常用降级策略:

    • 回退到缓存: 如果主数据源(例如,数据库、外部 API)不可用,则回退到从本地或分布式缓存中提供数据。
    • 返回默认值: 当服务不可用时,返回预定义的默认值或静态数据,而不是动态结果。
    • 简化功能: 在中断期间禁用非必要的功能或特性,以降低负载并维护核心服务。 例如,在电子商务网站中,你可能会在高峰负载期间暂时禁用产品推荐,但保持核心产品浏览和订购功能正常工作。
    • 静态内容: 当动态内容生成失败或缓慢时,从 CDN 或本地存储提供静态内容(例如,HTML 页面、图像)。
    • 熔断器回退: 当熔断器打开时(见下一节),它通常会触发回退机制。
  • Spring Boot 实现选项:

    • Resilience4j @FallbackMethod Resilience4j 的 @CircuitBreaker 和其他弹性注解允许你指定一个 fallbackMethod。 如果带注解的方法失败或熔断器打开,将执行此方法。
    • Hystrix Fallback (遗留): Netflix Hystrix(现在处于维护模式)也使用命令模式和 getFallback() 方法提供了强大的回退机制。
    • 服务中的条件逻辑: 你可以在你的 Spring Boot 服务中直接实现降级逻辑。 这涉及检查服务可用性、资源使用情况或错误条件,并执行替代代码路径(例如,使用 if/else 语句、try-catch 块)。
    • 面向切面编程 (AOP): 你可以使用 AOP 创建可重用的降级逻辑,该逻辑可以应用于多个服务或方法。
    • 外部配置: 使用外部配置(例如,Spring Cloud Config、Consul、etcd)根据系统运行状况动态地启用或禁用功能,或在不同的服务实现之间切换。
  • 示例 (Resilience4j @FallbackMethod):

    import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
    import org.springframework.stereotype.Service;@Service
    public class ProductService {@CircuitBreaker(name = "productServiceCB", fallbackMethod = "getProductFallback")public String getProductDetails(String productId) {// 模拟潜在的服务故障if (Math.random() < 0.3) {throw new RuntimeException("产品服务已关闭!");}return "产品 ID 为: " + productId + " 的详细信息"; // 正常服务响应}// 回退方法 - 当 getProductDetails 失败或熔断器打开时执行public String getProductFallback(String productId, Throwable throwable) {return "产品详细信息目前不可用。请稍后重试或稍后查看。"; // 降级响应}
    }
    

3. 熔断 (Circuit Breaking)

  • 定义: 熔断是一种模式,灵感来自电气断路器。 它用于防止应用程序重复尝试调用可能失败的服务。 就像物理断路器一样,当检测到故障时,它会“打开”电路,并将请求重定向到回退或在一段时间内完全阻止它们。

  • 目的:

    • 防止级联故障(再次强调!): 熔断对于防止分布式系统中的级联故障至关重要。 当依赖项开始失败时,熔断器会快速停止对该失败依赖项的进一步请求,从而防止你的服务因等待超时而陷入困境,并可能导致资源耗尽。
    • 快速失败和快速恢复: 熔断器允许快速失败,而不是长时间延迟和超时等待失败的服务。 它会立即返回失败响应或触发回退机制。 它还可以实现更快的恢复,因为熔断器可以在一段时间后“自愈”,并自动尝试重新建立与依赖项的连接。
    • 保护故障服务: 通过停止对故障服务的请求,熔断器使该服务有时间恢复,而不会因持续的请求而进一步过载。
    • 提高系统稳定性: 熔断器通过隔离故障并防止其蔓延,显着提高了分布式系统的整体稳定性和弹性。
  • 熔断器状态:

    • 关闭 (Closed): 正常运行。 请求会传递到依赖项。 熔断器监控请求的成功/失败率。
    • 打开 (Open): 当失败率超过配置的阈值时,熔断器会“打开”。 在打开状态下,所有后续对依赖项的请求都会立即失败(或重定向到回退),而无需尝试调用依赖项。
    • 半开 (Half-Open): 在打开状态下经过配置的“等待持续时间”后,熔断器会转换为半开状态。 在此状态下,它允许有限数量的“探测”请求传递到依赖项。 如果这些探测请求成功,则熔断器再次关闭(返回到关闭状态)。 如果它们失败,则熔断器重新打开(返回到打开状态),并且等待持续时间计时器重置。
  • 熔断器指标(触发条件):

    • 错误率阈值: 在一段时间或请求的滑动窗口内,失败请求的百分比。 当超过此阈值时,熔断器会打开。
    • 故障计数阈值: 滑动窗口内故障的绝对数量。
    • 慢调用率阈值: 超过配置的慢调用持续时间阈值的请求百分比。
    • 组合指标: 熔断器可以使用这些指标的组合来确定何时打开。
  • Spring Boot 实现选项:

    • Resilience4j @CircuitBreaker Resilience4j 使用 @CircuitBreaker 注解和编程 API 提供了强大的熔断器实现。 它是 Hystrix 的现代且积极维护的替代方案。
    • Hystrix @HystrixCommand (遗留): Netflix Hystrix 是最初流行的 Java 熔断器库。 虽然现在处于维护模式,但许多较旧的 Spring Boot 项目仍在使用 Hystrix。
    • Spring Cloud Circuit Breaker (抽象): Spring Cloud 提供了一个 spring-cloud-starter-circuitbreaker 抽象,允许你在不同的熔断器实现(如 Resilience4j 或 Hystrix)之间切换,而无需显着更改你的应用程序代码。
    • Sentinel: Sentinel 还包括熔断功能,作为其更广泛的流量控制和弹性功能的一部分。
    • 自定义实现: 你可以构建自己的熔断器逻辑,但通常建议使用像 Resilience4j 或 Hystrix 这样的已建立的库,因为它们处理了状态管理、计时器和线程安全性的复杂性。
  • 示例 (Resilience4j @CircuitBreaker):

    import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
    import org.springframework.stereotype.Service;@Service
    public class InventoryService {@CircuitBreaker(name = "inventoryServiceCB", fallbackMethod = "getInventoryFallback")public int checkInventory(String productId) {// 模拟调用可能失败的库存服务if (Math.random() < 0.4) {throw new RuntimeException("库存服务不可用!");}return 100; // 假设库存可用}public int getInventoryFallback(String productId, Throwable throwable) {// 当服务不可用时,返回默认库存级别return 0; // 表示没有库存可用(降级响应)}
    }
    

总结:

  • 限流: 控制进入你的应用程序的流量,以防止过载。
  • 降级: 当服务不可用时,提供降低的功能替代响应,保持核心功能和用户体验。
  • 熔断: 停止向失败的依赖项发送请求,防止级联故障,实现快速失败,并允许更快地恢复。

这三种机制对于构建健壮、可扩展且容错的 Spring Boot 微服务至关重要,这些微服务可以承受高流量、依赖故障以及分布式环境中的其他挑战。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/23790.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

政安晨【零基础玩转各类开源AI项目】DeepSeek 多模态大模型Janus-Pro-7B,本地部署!支持图像识别和图像生成

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 目录 下载项目 创建虚拟环境 安装项目依赖 安装 Gradio&#xff08;UI&#xff09; 运…

在 Mac mini M2 上本地部署 DeepSeek-R1:14B:使用 Ollama 和 Chatbox 的完整指南

随着人工智能技术的飞速发展&#xff0c;本地部署大型语言模型&#xff08;LLM&#xff09;已成为许多技术爱好者的热门选择。本地部署不仅能够保护隐私&#xff0c;还能提供更灵活的使用体验。本文将详细介绍如何在 Mac mini M2&#xff08;24GB 内存&#xff09;上部署 DeepS…

【Godot4.3】基于绘图函数的矢量蒙版效果与UV换算

概述 在设计圆角容器时突发奇想&#xff1a; 将圆角矩形的每个顶点坐标除以对应圆角矩形所在Rect2的size&#xff0c;就得到了顶点对应的UV坐标。然后使用draw_colored_polygon&#xff0c;便可以做到用图片填充圆角矩形的效果。而且这种计算的效果就是图片随着其填充的图像缩…

51单片机-AT24CXX存储器工作原理

1、AT24CXX存储器工作原理 1.1、特点&#xff1a; 与400KHz&#xff0c;I2C总线兼容1.8到6.0伏工作电压范围低功耗CMOS技术写保护功能当WP为高电平时进入写保护状态页写缓冲器自定时擦写周期100万次编程/擦除周期可保存数据100年8脚DIP SOIC或TSSOP封装温度范围商业级和工业级…

Linux网络 网络层

IP 协议 协议头格式 4 位版本号(version): 指定 IP 协议的版本, 对于 IPv4 来说, 就是 4. 4 位头部长度(header length): IP 头部的长度是多少个 32bit, 也就是 4 字节&#xff0c;4bit 表示最大的数字是 15, 因此 IP 头部最大长度是 60 字节. 8 位服务类型(Type Of Service):…

Unity百游修炼(1)——FootBall详细制作全流程

一、引言 游玩测试&#xff1a; Football 游玩测试 1.项目背景与动机 背景&#xff1a;在学习 Unity 的过程中&#xff0c;希望通过实际项目来巩固所学知识&#xff0c;同时出于对休闲小游戏的喜爱&#xff0c;决定开发一款简单有趣的小游戏加深自己的所学知识点。 动机&#…

C语言(13)------------>do-while循环

1.do-while循环的语法 我们知道C语言有三大结构&#xff0c;顺序、选择、循环。我们可以使用while循环、for循环、do-while循环实现循环结构。之前的博客中提及到了前两者的技术实现。可以参考&#xff1a; C语言&#xff08;11&#xff09;-------------&#xff1e;while循…

【1】VS Code 新建上位机项目---C#基础语法

VS Code 新建上位机项目---C#基础语法 1 基本概念1.1 准备工具1.2 新建项目2 C#编程基础2.1 命名空间和类2.2 数据类型2.3 控制台输入输出2.3.1 输入输出: write 与 read2.3.2 格式化 : string.Foramt() 与 $2.3.3 赋值与运算2.4 类型转换2.4.1 数值类型之间的转换:(int)2.4…

SQL:DQL数据查询语言以及系统函数(oracle)

SQL Structured Query Language&#xff0c;结构化查询语言, 是一种用于管理和操作关系数据库的标准编程语言。 sql的分类 DQL&#xff08;Data Query Language&#xff09;&#xff1a;数据查询语言 DDL&#xff08;Data Definition Language&#xff09;&#xff1a;数据…

从单片机的启动说起一个单片机到点灯发生了什么下——使用GPIO点一个灯

目录 前言 HAL库对GPIO的抽象 核心分析&#xff1a;HAL_GPIO_Init 前言 我们终于到达了熟悉的地方&#xff0c;对GPIO的初始化。经过漫长的铺垫&#xff0c;我们终于历经千辛万苦&#xff0c;来到了这里。关于GPIO的八种模式等更加详细的细节&#xff0c;由于只是点个灯&am…

提效10倍:基于Paimon+Dolphin湖仓一体新架构在阿里妈妈品牌业务探索实践

1. 业务背景 阿里妈妈品牌广告数据包括投放引擎、下发、曝光、点击等日志&#xff0c;面向运筹调控、算法特征、分析报表、诊断监控等应用场景&#xff0c;进行了品牌数仓能力建设。随着业务发展&#xff0c;基于Lambda架构的数仓开发模式&#xff0c;缺陷日益突出&#xff1a;…

一文详解U盘启动UEFI/Legacy方式以及GPT/MBR关系

对于装系统的老手而说一直想研究一下装系统的原理&#xff0c;以及面对一些问题时的解决思路&#xff0c;故对以前的方法进行原理上的解释&#xff0c;主要想理解其底层原理。 引导模式 MBR分区可以同时支持UEFI和Legacy引导&#xff0c;我们可以看一下微pe制作的启动盘&#…

基于Docker的前端环境管理:从开发环境到生产部署的实现方案

# 基于Docker的前端环境管理&#xff1a;从开发环境到生产部署的实现方案 简介及前端开发环境挑战 简介 是一种容器化平台&#xff0c;可以将应用程序及其依赖项打包为一个容器&#xff0c;提供一种轻量级、可移植的环境。它能够简化开发、部署和运维的流程&#xff0c;提高…

连锁管理系统的五大核心设计及 PHP 源码分享

在当今竞争激烈的连锁商业领域&#xff0c;高效的管理系统是企业脱颖而出的关键。商淘云连锁管理系统凭借其卓越的功能和灵活的架构&#xff0c;为连锁企业提供了强大的运营支持。在这里详细介绍其五大核心设计&#xff0c;并分享相关的 PHP 源码示例。 一、总部进销存管理 &a…

C语言基本知识------指针(4)

1. 回调函数是什么&#xff1f; 回调函数就是⼀个通过函数指针调用的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另⼀个函数&#xff0c;当这个指针被⽤来调⽤其所指向的函数 时&#xff0c;被调⽤的函数就是回调函数。 void qsort(void base,//指针…

MTK-Android13-包安装器PackageInstaller 静默安装实现

目的 我们最终是为了搞明白安装的整个流程。一方面通过安卓系统自带的包安装器来了解PMS 安装流程&#xff1b;另一方面熟悉框架层Framework 针对Android apk 安装流程。 前两篇文章分析了PackagerInstaller 安装流程。 Android13-包安装器PackageInstaller-之apk安装跳转 An…

qt-C++笔记之创建和初始化 `QGraphicsScene` 和 `QGraphicsView` 并关联视图和场景的方法

qt-C++笔记之创建和初始化 QGraphicsScene 和 QGraphicsView 并关联视图和场景的方法 code review! 参考笔记 1.qt-C++笔记之创建和初始化 QGraphicsScene 和 QGraphicsView 并关联视图和场景的方法 2.qt-C++笔记之QGraphicsScene和 QGraphicsView中setScene、通过scene得到vie…

《一起打怪兽吧》——自制一款Python小游戏

《一起消灭怪兽吧》——在深夜的屏幕前&#xff0c;你是指引光明的勇者。键盘化作利剑&#xff0c;用方向键在像素战场游走&#xff0c;发射吧&#xff0c;每次击杀都有代码绽放的烟火。这款由Python与Pygame铸就的小游戏&#xff0c;让0与1的世界生长出童真的浪漫。 文章目录…

IDEA中查询Maven项目的依赖树

在Maven项目中&#xff0c;查看项目的依赖树是一个常见的需求&#xff0c;特别是当你需要了解项目中直接或间接依赖了哪些库及其版本时。你可以通过命令行使用Maven的dependency:tree插件来做到这一点。这个命令会列出项目中所有依赖的树状结构。 打开idea项目的终端&#xff…

Maven——Maven开发经验总结(1)

摘要 本文总结了 Maven 开发中的多个关键经验&#xff0c;包括如何根据版本号决定推送到 releases 或 snapshots 仓库&#xff0c;如何在构建过程中跳过测试&#xff0c;父项目如何控制子项目依赖版本&#xff0c;父项目依赖是否能传递到子项目&#xff0c;如何跳过 Maven dep…