手写Hystrix基本原理

news2024/12/26 10:44:44
本文已收录于专栏
《中间件合集》

目录

  • 概念说明
    • 什么是Hystrix
    • Hystrix解决的问题
  • 提供服务
  • 工作流程
  • 代码实现
    • HystrixSDK
      • MyHystrixCommand注解
      • MyHystrixProperty注解
      • MyAspect注解解释器
    • 发送请求端
      • 引入Hystrix的依赖
      • 调用代码
    • 接收请求端
    • 执行效果
      • 发送请求端
  • 总结提升

概念说明

什么是Hystrix

  Spring Cloud Hystrix 是基于 Netflix 公司的开源组件 Hystrix 实现的,它提供了熔断器功能,能够有效地阻止分布式微服务系统中出现联动故障,以提高微服务系统的弹性。Spring Cloud Hystrix 具有服务降级、服务熔断、线程隔离、请求缓存、请求合并以及实时故障监控等强大功能。

Hystrix解决的问题

在这里插入图片描述
  所有服务都需要请求服务T,当B服务有大量的请求,导致服务T所属的服务器CPU太高,无法立即处理请求,导致服务瘫痪。瘫痪之后就会导致所有的请求推挤在服务U然后一直向上堆积。这时候当服务A去访问服务T或者服务U的时候也请求不同。导致整个体统都瘫痪了。我们把这个情况成为灾难性的雪崩效应。Hystrix 就能很好的解决这一问题。

提供服务

Spring Cloud Hystrix提供了一系列强大的功能来处理分布式系统中的延迟和容错问题。下面是对这些功能的详细说明:

  1. 「 服务降级(Fallback)」:当一个服务发生故障或超时时,Hystrix可以提供一个备用的响应或执行一些预定义的逻辑,从而避免对整个系统的影响。通过定义降级逻辑,例如返回默认值、执行备用方法或从缓存中获取数据,可以保证系统的可用性。
  2. 「 服务熔断(Circuit Breaker)」:Hystrix可以根据一定的条件自动开启或关闭服务的熔断。当服务调用失败率达到一定阈值时,Hystrix会自动开启熔断,之后的请求将直接返回降级的响应,避免对后端服务的继续调用,从而保护后端服务免受进一步的压力。一段时间后,Hystrix会尝试恢复对服务的调用,如果调用成功,则关闭熔断,否则继续开启熔断。
  3. 「 线程隔离(Thread Isolation)」:Hystrix通过使用线程池隔离不同的服务调用,可以防止一个服务的故障导致整个系统的故障。每个服务都运行在独立的线程池中,从而提供了更好的资源隔离和保护。这样可以避免由于一个服务的延迟或故障导致其他服务的阻塞。
  4. 「 请求缓存(Request Caching)」:Hystrix可以缓存相同的请求结果,以避免重复的调用。当多个请求需要调用同一个服务时,Hystrix会先从缓存中查找结果,如果存在则直接返回,而不需要再次调用服务。这样可以减少对后端服务的请求次数,提高系统的性能和吞吐量。
  5. 「请求合并(Request Collapsing) 」:Hystrix可以将多个相同类型的请求合并为一个批量请求,从而减少网络开销和提高系统的性能。当多个请求需要调用同一个服务时,Hystrix会将这些请求合并为一个批量请求,并一次性发送给后端服务,然后将结果拆分返回给各个请求。这样可以减少网络通信的次数,提高系统的效率。
  6. 「 实时故障监控(Real-time Monitoring)」:Hystrix提供了实时监控和指标收集功能,可以通过Hystrix Dashboard或Turbine来查看服务的健康状况、请求的响应时间、错误率等指标。这样可以帮助开发人员快速发现和解决问题,保证系统的稳定性和可靠性。

  通过使用Spring Cloud Hystrix,我们可以更好地处理分布式系统中的故障和延迟问题,提高系统的可靠性和容错性。

工作流程

  当在5秒内A服务向B服务发送了10个请求,并且满足错误率达到50%。那么断路器开启,进行熔断机制,在30秒内不在请求B服务,直接请求我们定义的托底方法。这些参数例如5s、10个请求、错误率都是可以在代码中进行配置的。根据不同的需求填写不同的参数。
在这里插入图片描述

代码实现

HystrixSDK

sdk是每个请求的发送端需要引入的服务,使用sdk中的一些注解来完成具体的服务

MyHystrixCommand注解

package com.example.hystrixdemo.utils;


import com.netflix.hystrix.contrib.javanica.annotation.HystrixException;
import com.netflix.hystrix.contrib.javanica.annotation.ObservableExecutionMode;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited  //表示注解可以被子类继承
public @interface MyHystrixCommand {
    String groupKey() default "";

    String commandKey() default "";

    String threadPoolKey() default "";

    String fallbackMethod() default "";

    MyHystrixProperty[] commandProperties() default {};

    MyHystrixProperty[] threadPoolProperties() default {};

    Class<? extends Throwable>[] ignoreExceptions() default {};

    ObservableExecutionMode observableExecutionMode() default ObservableExecutionMode.EAGER;

    HystrixException[] raiseHystrixExceptions() default {};

    String defaultFallback() default "";

}

MyHystrixProperty注解

package com.example.hystrixdemo.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyHystrixProperty {
    String name();

    String value();
}

MyAspect注解解释器

package com.example.hystrixdemo.utils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Date;

/**
 * @BelongsProject: hystrixDemo
 * @BelongsPackage: com.example.hystrixdemo.utils
 * @Author: Wuzilong
 * @Description: 注解解释器
 * @CreateTime: 2023-09-21 10:50
 * @Version: 1.0
 */
@Aspect
@Component
public class MyAspect {

    Integer requestNum = 0;
    Date newTime = null;
    Date newDelayTime=null;
    Boolean isDelayTime = false;
    @AfterThrowing(pointcut = "execution(* com.example..*.*(..))",throwing = "ex")
    public Object afterThrowing(JoinPoint joinPoint,Exception ex) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

        try {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method1 = methodSignature.getMethod();
            if (method1.isAnnotationPresent(MyHystrixCommand.class)) {
                MyHystrixCommand annotation = method1.getAnnotation(MyHystrixCommand.class);
                MyHystrixProperty[] myHystrixProperties = annotation.commandProperties();

                if (myHystrixProperties.length == 0) {
                    Method method2 = joinPoint.getTarget().getClass().getMethod(annotation.fallbackMethod());
                    return method2.invoke(joinPoint.getTarget());
                } else {
                    if (newDelayTime != null && new Date().compareTo(newDelayTime)>=0) {
                        isDelayTime=false;
                        newTime = null;
                        newDelayTime=null;
                    }
                    if (isDelayTime) {
                        Method method2 = joinPoint.getTarget().getClass().getMethod(annotation.fallbackMethod());
                        method2.invoke(joinPoint.getTarget());
                    } else {
                        String numValue = null;
                        String timeValue = null;
                        String errorRateValue = null;
                        String delayTimeValue = null;

                        for (MyHystrixProperty property : myHystrixProperties) {

                            if (property.name().equals("requestNum")) {
                                numValue = property.value();
                            } else if (property.name().equals("requestTime")) {
                                timeValue = property.value();
                            } else if (property.name().equals("requestErrorRate")) {
                                errorRateValue = property.value();
                            } else if (property.name().equals("requestDelayTime")) {
                                delayTimeValue = property.value();
                            }
                        }
                        requestNum++;

                        if (newTime==null){
                            // 创建Calendar对象,并设置为当前时间
                            Calendar calendar = Calendar.getInstance();
                            calendar.setTime(new Date());
                            // 将Calendar对象的毫秒数加上任意值(这里假设增加1000毫秒)
                            calendar.add(Calendar.MILLISECOND, Integer.valueOf(timeValue));
                            newTime=calendar.getTime();
                        }
                        if (new Date().compareTo(newTime) >=0){
                            if (requestNum >= Integer.valueOf(numValue)) {
                                double i = Double.valueOf(numValue) / requestNum * 100;
                                if (i >= Integer.valueOf(errorRateValue)) {
                                    isDelayTime = true;
                                    if (newDelayTime==null){
                                        // 创建Calendar对象,并设置为当前时间
                                        Calendar calendar = Calendar.getInstance();
                                        calendar.setTime(new Date());
                                        // 将Calendar对象的毫秒数加上任意值(这里假设增加1000毫秒)
                                        calendar.add(Calendar.MILLISECOND, Integer.valueOf(delayTimeValue));
                                        newDelayTime=calendar.getTime();
                                    }
                                    requestNum = 0;
                                    Method method2 = joinPoint.getTarget().getClass().getMethod(annotation.fallbackMethod());
                                    return method2.invoke(joinPoint.getTarget());
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("通过异常进入到AOP中,调用了托底方法");

        }
        return null;
    }
}

  声明两个注解分别用来设置服务降级和熔断操作的。MyHystrixCommand注解中会指定降级的方法。其中也包括MyHystrixProperty注解来指定熔断操作开启的一些参数,例如请求的时间、请求的次数、请求错误率等等。MyAspect类去识别两个注解,处理对应的业务逻辑。

发送请求端

引入Hystrix的依赖

        <dependency>
            <groupId>com.example</groupId>
            <artifactId>hystrixDemo</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

调用代码

package com.example.useraservice.service;

import com.example.hystrixdemo.utils.MyHystrixCommand;
import com.example.hystrixdemo.utils.MyHystrixProperty;
import com.example.openfeigndemo.config.FeignConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @BelongsProject: UserAService
 * @BelongsPackage: com.example.useraservice.service
 * @Author: Wuzilong
 * @Description: 描述什么人干什么事儿
 * @CreateTime: 2023-07-26 08:40
 * @Version: 1.0
 */
@Service
public class UserA {

    @Autowired
    private FeignConfig feignConfig;

    @MyHystrixCommand(fallbackMethod = "errorMsg",commandProperties = {
            @MyHystrixProperty(name = "requestNum", value = "3"), //请求次数
            @MyHystrixProperty(name = "requestTime", value = "10000"), //请求的单位时间
            @MyHystrixProperty(name = "requestErrorRate", value = "50"),  //错误率
            @MyHystrixProperty(name = "requestDelayTime", value = "20000")   //熔断持续时间
    })
    public String userA(){
        System.out.println("进入A服务的方法了,去访问B服务。");
        IUserBService iUserBService=(IUserBService)feignConfig.getAgentObject();
        String returnContext = iUserBService.getServiceBInfo();
        System.out.println("B服务返回的内容是:"+returnContext);
        return "A服务调用B服务";
    }

    public String errorMsg()  {
        System.out.println("你有异常啦");
        return "你有异常了";
    }
}

package com.example.useraservice.controller;

import com.example.useraservice.service.UserA;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @BelongsProject: UserAService
 * @BelongsPackage: com.example.useraservice.controller
 * @Author: Wuzilong
 * @Description: 描述什么人干什么事儿
 * @CreateTime: 2023-07-26 15:44
 * @Version: 1.0
 */
@RestController
@RequestMapping("/serviceA")
public class UserAController {
    @Autowired
    private UserA userA;
    @RequestMapping(value="serviceAInfo",method= RequestMethod.GET)
    public void getServiceAInfo(){
        try{
            userA.userA();
        }catch (Exception e){
            System.out.println("通过异常进入到AOP中,已调用了托底方法");
        }

    }
}

接收请求端

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @BelongsProject: ServiceB
 * @BelongsPackage: com.example.serviceb.Controller
 * @Author: Wuzilong
 * @Description: B服务
 * @CreateTime: 2023-06-07 19:08
 * @Version: 1.0
 */
@RestController
@RequestMapping("/B")
public class ServiceBController {

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/receiveMessage")
    public String receiveMessage() throws UnknownHostException {

        System.out.println("B:我被调用了");
        //返回的内容是ip地址和端口号
        return InetAddress.getLocalHost().getHostAddress()+":"+serverPort;
    }
}

执行效果

发送请求端

在这里插入图片描述  B服务没有启动,所以在请求的过程中或报错,由于配置了hystrix所以在报错的时候会进行降级或者熔断操作。

总结提升

  Hystrix是一个强大的工具,可以帮助开发人员处理分布式系统中的故障和延迟问题,提高系统的可用性和性能。它的各种功能和特点使得开发人员能够更好地控制和管理系统的运行状态,提供更好的用户体验。


🎯 此文章对你有用的话记得留言+点赞+收藏哦🎯

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

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

相关文章

树莓集团又一力作,打造天府蜂巢成都直播产业园样板工程

树莓集团再次推出惊艳之作&#xff0c;以打造成都天府蜂巢直播产业园为目标。该基地将充分展现成都直播产业园的巨大潜力与无限魅力&#xff0c;成为一个真正的产业园样板工程。 强强联手 打造未来 成都天府蜂巢直播产业园位于成都科学城兴隆湖高新技术服务产业园内&#xff0…

毕业设计选题之Java+springboot线上蔬菜销售与配送系统(源码+调试+开题+lw)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

基于Java的药品管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

国庆节难忘回家路:趣事、风景、反思

文章目录 前言趣事游记旅途风光在人气爆棚的小七孔古桥大七孔在喯珠泻玉的拉雅瀑布奇异罕见的水上森林在云雾缭绕的鸳鸯湖在天然地宫——天钟洞飞瀑流泉 反思人们在死亡之前自己会有预感吗&#xff1f;求索生死大问 中秋国庆的规划后记 前言 中秋国庆&#xff0c;双节汇在一起…

8、绩效看板与日清计划

6、片花关联长视频 7、脏话检测 内容仓的办公区挂着几台电视&#xff0c;显示每个人目前完成的工作量&#xff0c;这就是绩效看板&#xff08;如下图&#xff09;&#xff0c;每位来参观的领导&#xff0c;都觉得这个绩效看板的想法很有意思。绩效看板是制造业常用的管理方法&…

【数据结构初阶】六、线性表中的队列(链式结构实现队列)

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 【数据结构初阶】五、线性表中的栈&#xff08;顺序表实现栈&#xff09;_高高的胖子的博客-CSDN博客 1 . 队列&#xff08;Queue&#xff09; 队列的概念和结构&#xff1a; 队列…

基于Java的食堂管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统功能具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域…

【设计模式】备忘录模式

文章目录 1.备忘录模式定义2.备忘录模式的角色3.备忘录模式实现3.1.场景说明3.2.结构类图3.3.代码实现 4.备忘录模式优缺点5.备忘录模式适用场景6.备忘录模式总结 主页传送门&#xff1a;&#x1f481; 传送 1.备忘录模式定义 备忘录&#xff08;Memento Pattern&#xff09;模…

图像处理: 马赛克艺术

马赛克 第一章 马赛克的历史渊源 1.1 马赛克 艺术中的一种表面装饰&#xff0c;由紧密排列的、通常颜色各异的小块材料&#xff08;如石头、矿物、玻璃、瓷砖或贝壳&#xff09;组成。与镶嵌不同的是&#xff0c;镶嵌是将要应用的部件放置在已挖空以容纳设计的表面中&#xff0…

ubuntu20安装nvidia驱动

1. 查看显卡型号 lspci | grep -i nvidia 我的输出&#xff1a; 01:00.0 VGA compatible controller: NVIDIA Corporation GP104 [GeForce GTX 1080] (rev a1) 01:00.1 Audio device: NVIDIA Corporation GP104 High Definition Audio Controller (rev a1) 07:00.0 VGA comp…

国庆周《Linux学习第三课》

国庆周《Linux学习第三课》 国庆周《Linux学习第二课》_IHOPEDREAM的博客-CSDN博客 总结 用户的管理 增加一个用户 删除一个用户 修改一个用户 查看一个用户 用户组的管理 增加一个组 删除一个组 修改一个组 查看一个组 将用户成员增加到该组中去 移除组的成员 1 用户

怎样在CSDN插入代码块 怎么变色?

添加代码块&#xff0c;通常有三种方式&#xff1a; 文章目录 ①点击 工具栏中的代码块 代码块 </>&#xff0c;② 快捷键 ctrlshiftk③ 先粘贴上代码&#xff0c;在选中 ctrlshiftk4 如果代码没有变彩色 ①点击 工具栏中的代码块 代码块 </>&#xff0c; 例如 选…

UWB技术在汽车智能制造的应用

返修区车辆管理项目 应用背景 在车辆总装生产线中&#xff0c;车辆下线后检测与返修是最后一个关键环节&#xff0c;整车一旦下线&#xff0c;由于流水线装配工艺、来料等原因&#xff0c;可能会出现部分整车存在瑕疵&#xff0c;进而进入返修区域待检。由于可能出现问题的不确…

探索设计模式:从组合到享元的软件架构之旅 (软件设计师笔记)

&#x1f600;前言 设计模式是软件开发中常见和经常使用的一种最佳实践方式&#xff0c;它们是为了解决在软件设计中反复出现的一类问题而提出的通用解决方案。本文主要探讨了四种设计模式&#xff1a;Composite&#xff08;组合&#xff09;、Decorator&#xff08;装饰器&…

Passper for Excel v3.7.3.4 Excel 密码恢复工具

网盘下载 Passper for Excel 是 Windows 上一款 Excel 密码恢复工具。可以恢复任何丢失或忘记的 Excel 文档密码。具有高恢复率和 100% 的数据安全性。支持通过 GPU 加速恢复密码&#xff0c;恢复速度提高 10 倍以上。 字典&#xff0c;根据内置或自定义词典恢复密码。 一般来…

【接口测试】测试基础

一、接口测试简介 1.接口测试的定义 接口测试是一种测试系统组件间接口的测试&#xff0c;主要目标是检测外部系统与系统之间以及内部各个子系统之间的交互点&#xff0c;以检查数据的交换、传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 随着前后端分离…

Visio如何对文本打下标、上标,以及插入公式编辑器等问题(已解决)

解决这个问题的本质问题&#xff0c;就是在Visio中插入公式编辑器&#xff08;这不是visio的常用命令&#xff0c;需要添加&#xff09;。 打开Visio--》文件--选项 点击选项&#xff0c;弹出对话框。在自定义功能区中&#xff0c;点击 常用命令&#xff0c;在下拉选项中&#…

【Ambari】银河麒麟V10 ARM64架构_安装Ambari2.7.6HDP3.3.1问题总结

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的帮助&#x1f338;文…

IDEA Debug技巧大全,看完就能提升工作效率

作者简介 目录 1.行断点 2.方法断点 3.异常断点 4.字段断点 5.条件表达式 1.行断点 行断点就是平时我们在代码行旁边单击鼠标打上的断点&#xff0c;这个没有什么好说的。关键点在于很多人不知道的&#xff0c;行断点其实是可以右击选择是对改行的全部调用都生效&#xf…

如何在Proteus进行STM32F103C8T6模拟以及keil5开发

一、下载Proteus 8和keil5 最新版 Proteus 8.15 Professional 图文安装教程&#xff08;附安装包&#xff09;_proteus密钥_main工作室的博客-CSDN博客Keil uVision5 5.38官方下载、安装及注册教程_keil uvision5下载_这是乐某的博客-CSDN博客 二、新建STM32F103C8项目 接下来…