和外部机构API交互如何防止外部机构服务不可用拖垮调用服务
引言
在现代的分布式系统和微服务架构中,服务之间的通信往往通过API进行,尤其是在与外部机构或第三方服务进行交互时,更需要通过API实现功能的集成。然而,由于外部服务的可控性较差,其服务的不可用性(如响应缓慢或服务宕机)可能会影响我们自己的服务调用,甚至会导致系统整体性能下降或崩溃。
为了避免外部机构的API不可用时拖垮我们的系统,我们需要设计合理的防护机制,包括熔断机制、限流机制、超时设置、重试机制、服务降级等手段。本文将深入探讨如何通过这些技术,构建一个高可用、健壮的服务交互系统,并结合代码示例详细讲解实现方案。
第一部分:外部API不可用的常见问题分析
1.1 API调用的挑战
当我们与外部服务或API进行交互时,可能会遇到如下问题:
- 网络问题:网络不稳定可能会导致请求延迟、超时等问题。
- 外部服务不可用:外部服务可能因为内部故障或流量过大而不可用,导致服务不可用。
- 响应时间过长:外部服务响应过慢会导致我们调用的系统阻塞,进而拖慢整个服务的响应时间。
- 服务负载过高:如果外部服务请求过多,而服务没有进行限流,会使得系统无法处理并导致崩溃。
- 不一致的错误处理:外部服务返回的错误可能并没有标准化处理,增加了对接的复杂性。
1.2 风险评估
与外部API的交互问题如果不加以控制,可能引发以下严重后果:
- 系统响应延迟:外部服务响应过慢,导致调用服务的响应时间也被拉长,进而影响用户体验。
- 系统崩溃:如果外部服务不可用,而我们的系统没有及时进行降级处理,可能会导致整个系统崩溃。
- 资源耗尽:不断重试或等待外部服务可能会导致系统资源耗尽,如线程、连接池等。
第二部分:设计原则与防护机制
为了避免外部服务不可用时拖垮我们的调用服务,我们需要建立多种防护机制。这些机制应遵循以下设计原则:
- 故障隔离:确保外部服务故障时,影响范围被隔离,不影响其他功能或模块。
- 容错机制:确保在外部服务失败时,系统能够有降级处理或重试机制,不至于完全不可用。
- 快速失败:在外部服务出现问题时,尽量快速失败,避免长时间阻塞调用线程。
2.1 超时设置
超时是避免外部服务响应过慢影响我们系统的基础措施。通过设置合理的超时,可以避免外部服务长时间不响应时导致调用服务的线程长时间等待,进而拖慢系统性能。
2.1.1 实现超时的示例
我们可以在进行HTTP请求时通过设置超时来控制请求的最大等待时间。
Java代码示例(使用HttpURLConnection
)
import java.net.HttpURLConnection;
import java.net.URL;public class ApiService {public String callExternalApi(String apiUrl) throws Exception {URL url = new URL(apiUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 设置连接超时和读取超时connection.setConnectTimeout(5000); // 5秒连接超时connection.setReadTimeout(5000); // 5秒读取超时if (connection.getResponseCode() == 200) {// 处理响应return "Success";} else {return "Error";}}
}
2.1.2 设置超时的意义
- 避免线程阻塞:在等待外部服务响应时,设置超时可以避免线程长时间阻塞,提高系统资源利用率。
- 快速失败:当外部服务未能在规定时间内响应时,系统能够快速返回失败结果,避免影响整体服务质量。
2.2 熔断机制
熔断机制是微服务架构中非常重要的容错机制。熔断器的核心思想是:当外部服务连续多次失败时,暂时停止对其的调用,避免系统资源继续浪费。
熔断器类似电路中的保险丝,它能防止系统因持续的错误调用而陷入崩溃状态。当某个服务出现大量调用失败时,熔断器会进入打开状态,短时间内拒绝所有请求,等到外部服务恢复正常时,再关闭熔断器,恢复调用。
2.2.1 熔断机制的核心流程
- 监控外部服务的调用情况。
- 设定失败阈值:当调用外部服务的失败率超过阈值时,熔断器开启。
- 熔断器开启后,快速失败:不再向外部服务发起调用,直接返回失败结果。
- 熔断器关闭:经过一段时间后,检测外部服务恢复正常,再继续调用。
2.2.2 实现熔断器的示例
我们可以使用Hystrix
或者Resilience4j
等库来实现熔断器机制。以下是使用Resilience4j
实现熔断的代码示例。
Java代码示例(使用Resilience4j
)
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;import java.time.Duration;public class ApiServiceWithCircuitBreaker {private CircuitBreaker circuitBreaker;public ApiServiceWithCircuitBreaker() {CircuitBreakerConfig config = CircuitBreakerConfig.custom().failureRateThreshold(50) // 失败率达到50%触发熔断.waitDurationInOpenState(Duration.ofSeconds(5)) // 熔断器打开状态保持5秒.slidingWindowSize(10) // 统计窗口大小.build();circuitBreaker = CircuitBreakerRegistry.of(config).circuitBreaker("externalService");}public String callExternalApi(String apiUrl) {return CircuitBreaker.decorateSupplier(circuitBreaker, () -> {// 调用外部API逻辑return "Success";}).get();}
}
2.2.3 熔断机制的优势
- 保护系统资源:当外部服务长时间不可用时,避免系统不断调用导致资源浪费。
- 快速失败,提升系统响应速度:当服务不可用时,熔断器能够及时拒绝请求,避免影响系统性能。
- 自动恢复:当外部服务恢复后,熔断器能够自动关闭,恢复正常调用。
2.3 限流机制
在高并发场景下,外部服务可能无法处理大量的并发请求。为了防止过载,我们可以在系统内部对外部API的调用进行限流,确保外部服务不会被拖垮。
常见的限流算法有:
- 令牌桶算法:通过发放令牌的方式控制请求的速率,只有拿到令牌的请求才能进行API调用。
- 漏桶算法:通过将请求排队进入漏桶中,按照固定的速率处理。
2.3.1 令牌桶限流的实现
以下是基于Guava
库的令牌桶限流示例:
Java代码示例(使用Guava
限流)
import com.google.common.util.concurrent.RateLimiter;public class ApiServiceWithRateLimiter {// 每秒钟允许5个请求private RateLimiter rateLimiter = RateLimiter.create(5.0);public String callExternalApi(String apiUrl) {// 请求前进行限流if (rateLimiter.tryAcquire()) {// 调用外部APIreturn "Success";} else {return "Rate limit exceeded";}}
}
2.3.2 限流机制的优势
- 避免外部服务过载:通过限流,能够确保在高并发场景下,外部服务不会因为请求过多而崩溃。
- 系统自我保护:在外部服务无法响应时,通过限流机制可以减少对外部服务的依赖,提升系统的稳定性。
2.4 重试机制
当外部API偶尔出现短暂的故障时,重试机制能够帮助系统
在一定范围内恢复。合理的重试策略能够提高系统的健壮性,减少瞬时故障的影响。
2.4.1 重试策略设计
重试机制需要慎重设计,以避免导致更多的问题:
- 重试次数:避免无限重试,一般限制在3次左右。
- 重试间隔:每次重试的间隔时间可以逐渐增加(指数退避策略),避免给外部服务造成更大的压力。
- 重试条件:只对某些特定的错误类型进行重试,如网络超时或502错误,而对于业务逻辑错误不应重试。
2.4.2 实现重试机制的示例
Java代码示例(使用Resilience4j
实现重试)
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;import java.time.Duration;public class ApiServiceWithRetry {private Retry retry;public ApiServiceWithRetry() {RetryConfig config = RetryConfig.custom().maxAttempts(3) // 最大重试次数3次.waitDuration(Duration.ofSeconds(2)) // 每次重试间隔2秒.build();retry = RetryRegistry.of(config).retry("externalService");}public String callExternalApi(String apiUrl) {return Retry.decorateSupplier(retry, () -> {// 调用外部APIreturn "Success";}).get();}
}
2.4.3 重试机制的优势
- 提升系统健壮性:短暂的网络故障或服务不可用可以通过重试机制自动恢复。
- 减少人为干预:当外部服务恢复正常时,重试机制可以自动重发请求,无需人为干预。
2.5 服务降级
当外部服务长期不可用或不稳定时,服务降级可以帮助系统减少对外部服务的依赖,保证核心功能的可用性。在服务降级中,系统会提供一个默认的响应或简化的功能,以应对外部服务故障带来的影响。
2.5.1 服务降级的场景
- 外部服务不可用:当外部服务宕机或长时间无响应时,调用本地的降级策略。
- 请求超时:当请求超时时,提供一个默认的响应结果,而不是直接失败。
2.5.2 实现服务降级的示例
我们可以使用Hystrix
或Resilience4j
来实现服务降级。以下是一个使用Resilience4j
实现服务降级的示例:
Java代码示例(服务降级)
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;import java.util.function.Supplier;public class ApiServiceWithFallback {private CircuitBreaker circuitBreaker;public ApiServiceWithFallback() {CircuitBreakerConfig config = CircuitBreakerConfig.custom().failureRateThreshold(50).build();circuitBreaker = CircuitBreakerRegistry.of(config).circuitBreaker("externalService");}public String callExternalApi(String apiUrl) {Supplier<String> apiCall = CircuitBreaker.decorateSupplier(circuitBreaker, () -> {// 调用外部APIreturn "Success";});return apiCall.getOrDefault("Fallback response");}
}
2.5.3 服务降级的优势
- 保持系统可用性:即使外部服务不可用,服务降级能够保证系统的核心功能正常运行。
- 提升用户体验:用户不会因为外部服务不可用而无法继续使用系统。
第三部分:图文结合的架构设计
3.1 系统整体架构图
为了更好地说明上述各项机制的结合应用,下面是一个完整的系统架构图,展示了在高并发场景下如何保护系统免受外部服务故障的影响。
+-----------------------------------------------+
| |
| 负载均衡器/网关 |
| |
+-----------------------------------------------+| |v v+-------------------+ +-------------------+| 调用服务A(限流) | | 调用服务B(限流) |+-------------------+ +-------------------+| |v v
+--------------------------------------------------------+
| 超时设置 | 熔断器 | 重试机制 | 服务降级 | |
|--------------------------------------------------------|
| 外部服务1 | 外部服务2 | 外部服务3 |
+--------------------------------------------------------+
第四部分:实战示例——外部支付接口的防护设计
以支付系统为例,我们可以假设系统需要调用第三方支付接口。在高并发下,支付接口可能会出现不可用或超时的情况,因此我们需要为其设置完善的防护机制。
4.1 支付接口调用流程
- 订单生成:用户发起订单后,系统生成支付订单。
- 调用支付接口:系统调用外部支付服务接口。
- 超时与重试:若支付接口响应超时,进行重试,重试次数限制为3次。
- 熔断与降级:若支付接口不可用或响应错误次数过多,系统进入熔断状态,调用本地降级处理,提示用户稍后再试。
4.2 支付接口调用代码实现
public class PaymentService {private CircuitBreaker circuitBreaker;private Retry retry;private RateLimiter rateLimiter;public PaymentService() {// 初始化熔断器CircuitBreakerConfig breakerConfig = CircuitBreakerConfig.custom().failureRateThreshold(50).waitDurationInOpenState(Duration.ofSeconds(10)).build();circuitBreaker = CircuitBreakerRegistry.of(breakerConfig).circuitBreaker("paymentService");// 初始化重试机制RetryConfig retryConfig = RetryConfig.custom().maxAttempts(3).waitDuration(Duration.ofSeconds(2)).build();retry = RetryRegistry.of(retryConfig).retry("paymentService");// 初始化限流器rateLimiter = RateLimiter.create(5.0); // 每秒5个请求}public String processPayment(String paymentRequest) {if (rateLimiter.tryAcquire()) {return Retry.decorateSupplier(retry, CircuitBreaker.decorateSupplier(circuitBreaker, () -> {// 调用外部支付APIreturn callPaymentApi(paymentRequest);})).get();} else {return "Rate limit exceeded. Please try again later.";}}private String callPaymentApi(String paymentRequest) {// 模拟外部支付API调用return "Payment Success";}
}
第五部分:总结与最佳实践
5.1 关键技术点回顾
- 超时设置:快速失败,避免长时间等待外部服务响应。
- 熔断机制:通过熔断器保护系统资源,防止外部服务故障时的连锁反应。
- 限流机制:防止高并发场景下对外部服务的过载调用。
- 重试机制:在短暂网络故障或偶发错误时,自动进行请求重试,提高系统健壮性。
- 服务降级:当外部服务不可用时,提供替代方案或默认响应,保持系统的核心功能可用。
5.2 最佳实践
- 分层防护:将限流、熔断、重试等机制分层应用,从网络层到应用层,确保每一层都能对外部服务故障进行处理。
- 合理配置:根据业务需求合理设置超时时间、熔断阈值、重试次数等参数,避免设置过度或不足。
- 监控与预警:通过监控系统对外部服务的调用状态进行监控,及时发现问题,并设置预警机制,防止问题扩大。
通过本文的详细讲解与代码示例,希望开发者能够深入理解与外部机构API交互时的防护设计原则与实现方法,构建出更具韧性、更加稳定的系统。
相关文章:
和外部机构API交互如何防止外部机构服务不可用拖垮调用服务
引言 在现代的分布式系统和微服务架构中,服务之间的通信往往通过API进行,尤其是在与外部机构或第三方服务进行交互时,更需要通过API实现功能的集成。然而,由于外部服务的可控性较差,其服务的不可用性(如响…...

自动猫砂盆真的有必要吗?买自动猫砂盆不看这四点小心害死猫。
现在越来越多铲屎官选择购买自动猫砂盆来代替自己给猫咪铲屎,可是自动猫砂盆真的有必要吗?要知道,在现在忙碌的生活中,有很多人因为工作上的忙碌而不小心忽视了猫咪,猫咪的猫砂盆堆满粪便,要知道猫砂盆一天…...

国外解压视频素材哪里找?五个海外解压视频素材网站推荐
国外解压视频素材哪里找?五个海外解压视频素材网站推荐 如果你正在寻找国外的解压视频素材,那么今天这篇文章一定能帮助你。无论是修牛蹄、洗地毯,还是切肥皂、玩解压游戏等,下面分享的几个网站都是你找到高质量海外解压视频素材…...

Android一个APP里面最少有几个线程
Android一个APP里面最少有几个线程 参考 https://www.jianshu.com/p/92bff8d6282f https://www.jianshu.com/p/8a820d93c6aa 线程查看 Android一个进程里面最少包含5个线程,分别为: main线程(主线程)FinalizerDaemon线程 终结者守护线程…...

位操作解决数组的花样遍历
文章目录 题目 一、思路: 二、代码 总结 题目 leetcodeT289 https://leetcode.cn/problems/game-of-life/description/ 一、思路: 这题思路很简单,对每个位置按照题目所给规则进行遍历,判断周围网格的活细胞数即可。但是题目要求…...

【面试宝典】深入Python高级:直戳痛点的题目演示(下)
目录 🍔 Python下多线程的限制以及多进程中传递参数的⽅式 🍔 Python是如何进⾏内存管理的? 🍔 Python⾥⾯如何拷⻉⼀个对象? 🍔 Python⾥⾯search()和match()的区别? 🍔 lambd…...

Hive数仓操作(十七)
一、Hive的存储 一、Hive 四种存储格式 在 Hive 中,支持四种主要的数据存储格式,每种格式有其特点和适用场景,不过一般只会使用Text 和 ORC : 1. Text 说明:Hive 的默认存储格式。存储方式:行存储。优点…...
工业和自动化领域常见的通信协议
在工业和自动化领域,有多种常见的通信协议,主要用于设备间的通信、数据传输和控制。 Modbus: 类型:串行通信协议用途:广泛用于工业自动化设备间的通信,如PLC、传感器和执行器。优点:简单、开放且…...

连夜爆肝收藏各大云服务新老用户优惠活动入口地址(内含免费试用1个月的地址),适用于小白,大学生,开发者,小企业老板....
具体请前往:云服务器优惠活动入口大全--收藏各主流云厂商的云服务器等系列产品的优惠活动入口,免费试用1个月活动入口,让新老用户都能根据使用场景和身份快速锁定优惠权益 经济下滑,被优化增多,大学生就业难࿰…...
SpringBoot+Redis+RabbitMQ完成增删改查
各部分分工职责 RabbitMQ负责添加、修改、删除的异步操作 Redis负责数据的缓存 RabbitMQ里面角色职责简单描述 RabbitMQ里面有几个角色要先分清以及他们的对应关系: 交换机、队列、路由键 交换机和队列是一对多 队列和路由键是多对多 然后就是消息的发送者&…...

【系统集成中级】线上直播平台开发项目质量管理案例分析
【系统集成中级】线上直播平台开发项目质量管理案例分析 一、案例二、小林在项目质量管理中存在的问题(一)计划阶段缺失(二)测试用例编制与执行问题(三)质量管理流程问题(四)质量保证…...

浪潮信息领航边缘计算,推动AI与各行业深度融合
在9月20日于安徽盛大召开的浪潮信息边缘计算合作伙伴大会上,浪潮信息指出,未来的计算领域将全面融入AI技术,特别是在企业边缘侧,智能应用特别是生成式人工智能应用正在迅速普及,这一趋势正引领边缘计算向边缘智算的方向…...

Koa2项目实战3 (koa-body,用于处理 HTTP 请求中的请求体)
以用户注册接口为例,需要在请求里携带2个参数:用户名(user_name)和密码(password)。 开发者需要在接口端,解析出user_name 、password。 在使用Koa开发的接口中,如何解析出请求携带…...
复盘20241012
1、 classpath "com.android.tools.build:gradle:8.5.1" 的版本 与distributionUrlhttps\://services.gradle.org/distributions/gradle-8.9-bin.zip的对应规则: Execution failed for task :app:compileDebugKotlin. 解决方案 切换 setting --> ot…...
泊松流负载均衡控制
目录 泊松流负载均衡控制 一、到达率λ 二、服务率μ 三、泊松流负载均衡控制 泊松流负载均衡控制 在探讨泊松流负载均衡控制时,我们主要关注的是到达率λ和服务率μ这两个核心参数。以下是对这两个参数及其在泊松流负载均衡控制中作用的详细解释: 一、到达率λ 定义:…...

3D打印矫形器市场报告:未来几年年复合增长率CAGR为10.8%
3D 打印矫形器是指使用 3D 打印技术制作的定制外部支撑装置。它们有助于稳定、引导、缓解或纠正肌肉骨骼状况,并根据个体患者的解剖结构进行设计,通常使用 3D 扫描和建模技术。3D 打印在矫形器方面的主要优势是能够生产精确适合患者解剖结构的定制装置&a…...

Richtek立锜科技线性稳压器 (LDO) 选型
一、什么是LDO? LDO也可称为低压差线性稳压器,适合从较高的输入电压转换成较低输出电压的应用,这种应用的功率消耗通常不是很大,尤其适用于要求低杂讯、低电流和输入、输出电压差很小的应用环境。 二、LDO的特性 LDO透过控制线性区调整管…...

Leetcode 前 k 个高频元素
使用最小堆算法来解决这道题目:相当于有一个容量固定为K的教室,只能容纳 K 个人,学生们逐个逐个进入该教室,当教室容量达到K人之后,每次进入一个新的学生后,我们将分数最低的学生(类似本题中的频率最低元素…...
[LeetCode] 面试题01.02 判定是否互为字符重拍
题目描述: 给定两个由小写字母组成的字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。 示例 1: 输入: s1 "abc", s2 "bca" 输出: true 示例 2&am…...

数据结构-4.5.KMP算法(旧版上)-朴素模式匹配算法的优化
朴素模式匹配算法最坏的情况: 一.实例: 第一轮匹配失败,开始下一轮的匹配: 不断的操作,最终匹配成功: 如上述图片所述,朴素模式匹配算法会导致时间开销增加, 优化思路:主…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...