服务熔断-熔断器设计

news2024/12/26 20:11:53

文章目录

  • 服务为什么需要熔断
  • 熔断器设计思想
  • 熔断器代码实现

服务为什么需要熔断

对于服务端采用的保护机制为服务限流。 对于服务调用端是否存在保护机制?
假如要发布一个服务 B,而服务 B 又依赖服务 C,当一个服务 A 来调用服务 B 时,服务 B 的业务逻辑调用服务 C,而这时服务 C 响应超时了,由于服务 B 依赖服务 C,C 超时直接导致 B 的业务逻辑一直等待,而这个时候服务 A 在频繁地调用服务 B,服务 B 就可能会因为堆积大量的请求而导致服务宕机。
在这里插入图片描述
在这里插入图片描述

由此可见,服务 B 调用服务 C,服务 C 执行业务逻辑出现异常时,会影响到服务 B,甚至可能会引起服务 B 宕机。这还只是 A->B->C 的情况,试想一下 A->B->C->D->……呢?在整个调用链中,只要中间有一个服务出现问题,都可能会引起上游的所有服务出现一系列的问题,甚至会引起整个调用链的服务都宕机,这是非常恐怖的。
所以说,在一个服务作为调用端调用另外一个服务时,为了防止被调用的服务出现问题而影响到作为调用端的这个服务,这个服务也需要进行自我保护。而最有效的自我保护方式就是熔断。

熔断器设计思想

熔断状态实现包括三个:闭合、断开、半开,分别对应于正常、故障、检测故障是否已被修复的场景。

  1. 闭合:正常情况,后台会对调用失败次数进行积累,到达一定阈值或比例时则自动启动熔断机制。
  2. 断开:一旦对服务的调用失败次数达到一定阈值时,熔断器就会打开,这时候对服务的调用将直接返回一个预定的错误,而不执行真正的网络调用。同时,熔断器需要设置一个固定的时间间隔,当处理请求达到这个时间间隔时会进入半熔断状态。
  3. 半开:在半开状态下,熔断器会对通过它的部分请求进行处理,如果对这些请求的成功处理数量达到一定比例则认为服务已恢复正常,就会关闭熔断器,反之就会打开熔断器。

熔断设计的一般思路是,在请求失败 N 次后在 X 时间内不再请求,进行熔断;然后再在 X 时间后恢复 M% 的请求,如果 M% 的请求都成功则恢复正常,关闭熔断,否则再熔断 Y 时间,依此循环。在熔断的设计中,根据 Netflix 的开源组件 hystrix 的设计,我们可以仿照以下二个模块:熔断请求判断算法、熔断恢复机制:
熔断请求判断机制算法:根据事先设置的在固定时间内失败的比例来计算。
熔断恢复:对于被熔断的请求,每隔 X 时间允许部分请求通过,若请求都成功则恢复正常。

熔断器代码实现

在这里插入图片描述

package main.version4.v1.client.circuitBreaker;


import java.util.concurrent.atomic.AtomicInteger;

/**
 * 管理熔断器的状态,并根据请求的成功和失败的情况进行状态转移
 */
public class CircuitBreaker {
    // 当前状态
    private CircuitBreakerStatus status = CircuitBreakerStatus.CLOSED;
    private AtomicInteger failureCount = new AtomicInteger(0);
    private AtomicInteger successCount = new AtomicInteger(0);
    private AtomicInteger requestCount = new AtomicInteger(0);

    // 失败次数阈值
    private final int failureThreshold;
    // 半开启-》关闭状态的成功次数的比例
    private final double halfOpenSuccessRate;
    // 恢复时间
    private final long retryTimePeriod;
    // 上一次失败时间
    private long lastFailureTime = 0;
    public CircuitBreaker(int failureThreshold, double halfOpenSuccessRate, long retryTimePeriod){
        this.failureThreshold = failureThreshold;
        this.halfOpenSuccessRate = halfOpenSuccessRate;
        this.retryTimePeriod = retryTimePeriod;
    }

    // 查看当前熔断器是否允许请求通过
    public boolean allowRequest(){
        long currentTime = System.currentTimeMillis();
        switch (status){
            case OPEN:
                // 当前处于打开状态,超过一定时间,进入半开状态
                if(currentTime - lastFailureTime > retryTimePeriod){
                    // 细化锁的粒度,将锁从allowRequest判断中移除
                    synchronized (this){
                        if(status == CircuitBreakerStatus.OPEN){
                            status = CircuitBreakerStatus.HALF_OPEN;
                            resetCounts();
                            return true;
                        }
                    }
                }
                return false;
            case HALF_OPEN:
                // 在半开状态下,熔断器允许请求通过,并根据请求的成功率决定是否恢复到闭合状态或重新进入打开状态。
                requestCount.incrementAndGet();
                return true;
            case CLOSED:
            default:
                return true;
        }
    }

    // 记录成功
    public synchronized void recordSuccess(){
        if(status == CircuitBreakerStatus.HALF_OPEN) {
            // 半开状态下,统计成功的请求数量,当成功请求数量达到阈值后,关闭熔断器
            successCount.incrementAndGet();
            if (successCount.get() >= halfOpenSuccessRate * requestCount.get()) {
                status = CircuitBreakerStatus.CLOSED;
                resetCounts();
            }
        }else if(status == CircuitBreakerStatus.CLOSED){
            // 当熔断器关闭时,不清空数据
        }else{
            resetCounts();
        }
    }
    // 记录失败
    public synchronized void recordFailure(){
        failureCount.incrementAndGet();
        lastFailureTime = System.currentTimeMillis();
        if(status == CircuitBreakerStatus.HALF_OPEN){
            // 在半开状态下,请求再次失败,此时再次打开熔断器
            status = CircuitBreakerStatus.OPEN;
            lastFailureTime = System.currentTimeMillis();
        }else if(failureCount.get() > failureThreshold){
            // 失败次数达到阈值,熔断器进入打开状态,拒绝请求
            status = CircuitBreakerStatus.OPEN;
        }
    }

    // 重置次数
    public void resetCounts(){
        failureCount.set(0);
        successCount.set(0);
        requestCount.set(0);
    }
    // 获取状态
    public CircuitBreakerStatus getStatus(){
        return status;
    }
}

enum CircuitBreakerStatus{
    // 关闭、开启、半开启
    CLOSED, OPEN, HALF_OPEN
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Maven】依赖冲突如何解决?

准备工作 1、创建一个空工程 maven_dependency_conflict_demo,在 maven_dependency_conflict_demo 创建不同的 Maven 工程模块,用于演示本文的一些点。 什么是依赖冲突? 当引入同一个依赖的多个不同版本时,就会发生依赖冲突。…

代理IP地址的含义与设置指南‌

在数字化时代,互联网已经成为我们日常生活不可或缺的一部分。然而,在享受互联网带来的便利的同时,我们也面临着隐私泄露、访问限制等问题。代理IP地址作为一种有效的网络工具,能够帮助我们解决这些问题。本文将详细介绍代理IP地址…

【MyBatis】验证多级缓存及 Cache Aside 模式的应用

文章目录 前言1. 多级缓存的概念1.1 CPU 多级缓存1.2 MyBatis 多级缓存 2. MyBatis 本地缓存3. MyBatis 全局缓存3.1 MyBatis 全局缓存过期算法3.2 CacheAside 模式 后记MyBatis 提供了缓存切口, 采用 Redis 会引入什么问题?万一遇到需强一致场景&#x…

组播基础实验

当需要同时发给多个接受者或者接收者ip未知时使用组播 一、组播IP地址 1、组播IP地址范围 组播地址属于D类地址:224.0.0.0/4(224.0.0.0-239.255.255.255) 2、分类 (1)链路本地地址(link-local&#xf…

智慧银行反欺诈大数据管控平台方案(二)

智慧银行反欺诈大数据管控平台建设方案,通过系统性整合多元化数据源,融合先进的大数据处理与机器学习技术,构建一个具备实时性、智能性和高度集成能力的反欺诈系统框架。该方案以提升银行风险管理效率与精度为目标,创新性地采用多…

(免费送源码)计算机毕业设计原创定制:Java+ssm+JSP+Ajax SSM棕榈校园论坛的开发

摘要 随着计算机科学技术的高速发展,计算机成了人们日常生活的必需品,从而也带动了一系列与此相关产业,是人们的生活发生了翻天覆地的变化,而网络化的出现也在改变着人们传统的生活方式,包括工作,学习,社交…

#渗透测试#红蓝攻防#HW#漏洞挖掘#漏洞复现01-笑脸漏洞(vsftpd)

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…

手机控制载货汽车一键启动无钥匙进入广泛应用

移动管家载货汽车一键启动无钥匙进入手机控车系统‌, 该系统广泛应用于物流运输、工程作业等货车场景,为车主提供了高效、便捷的启动和熄火解决方案,体现了科技进步对物流行业的积极影响‌ 核心功能‌:简化启动流程,提…

OGRE 3D----5. OGRE和QML事件交互

在现代图形应用程序开发中,OGRE(Object-Oriented Graphics Rendering Engine)作为一个高性能的3D渲染引擎,广泛应用于游戏开发、虚拟现实和仿真等领域。而QML(Qt Modeling Language)则是Qt框架中的一种声明式语言,专注于设计用户界面。将OGRE与QML结合,可以充分利用OGR…

macos下brew安装redis

首先确保已安装brew,接下来搜索资源,在终端输入如下命令: brew search redis 演示如下: 如上看到有redis资源,下面进行安装,执行下面的命令: brew install redis 演示效果如下: …

汽车轮毂结构分析有哪些?国产3D仿真分析实现静力学+模态分析

本文为CAD芯智库原创,未经允许请勿复制、转载! 之前分享了如何通过国产三维CAD软件如何实现「汽车/汽配行业产品设计」,兼容NX(UG)、Creo(Proe),轻松降低企业上下游图纸交互成本等。…

Kafka的消费消息是如何传递的?

大家好,我是锋哥。今天分享关于【Kafka的消费消息是如何传递的?】面试题。希望对大家有帮助; Kafka的消费消息是如何传递的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中,消息的消费是通过消费…

常见靶场的搭建

漏洞靶场 渗透测试(漏洞挖掘)切忌纸上谈兵,学习渗透测试(漏洞挖掘)知识的过程中,我们通常需要一个包含漏洞的测试环境来进行训练。而在非授权情况下,对于网站进行渗透测试攻击,是触及…

PMP–一、二、三模、冲刺–分类–8.质量管理

文章目录 技巧五、质量管理 一模8.质量管理--质量管理计划--质量管理计划包括项目采用的质量标准,到底有没有满足质量需求,看质量标准即可。6、 [单选] 自项目开始以来,作为项目经理同事的职能经理一直公开反对该项目,在讨论项目里…

mini-spring源码分析

IOC模块 关键解释 beanFactory:beanFactory是一个hashMap, key为beanName, Value为 beanDefination beanDefination: BeanDefinitionRegistry,BeanDefinition注册表接口,定义注册BeanDefinition的方法 beanReference:增加Bean…

智能云在线编辑网站(完结篇)

开始及初步计划 1.前端tiptip编辑器框架vue3 2.后端Pythonflaskmysql 3.大模型调用:飞桨系列(ppasr) 前言:以此篇谨记从软件杯到天津生成式ai答辩过程及结束。 『如蚍蜉见青天,双肩难挑日月』,感叹世事多…

TETFN情感计算的实践复现

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

使用zabbix监控k8s

一、 参考文献 小阿轩yx-案例:Zabbix监控kubernetes云原生环境 手把手教你实现zabbix对Kubernetes的监控 二、部署经验 关于zabbix监控k8s,总体来说是分为两块内容,一是在k8s集群部署zabbix-agent和zabbix- proxy。二是在zabbix进行配置。…

【开源免费】基于Vue和SpringBoot的周边产品销售网站(附论文)

博主说明:本文项目编号 T 061 ,文末自助获取源码 \color{red}{T061,文末自助获取源码} T061,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

Lumos学习王佩丰Excel第十八讲:LOOKUP函数与数组

一、回顾统计函数 1、使用SUMIF函数 sumif(条件区域,求和条件,求和区域) 2、使用SUMIFS函数 SUMIFS(求和范围, 条件范围1, 条件1, 条件范围2, 条件2, ...) 二、认识数组 1、数组生成原理 所谓数组,是有序的元素序列。组成数组的各个变量称为数组的元素。对于Ex…