SpringCloud-Hystrix(断路器)

SpringCloud Hystrix

引言
微服务中有一个服务响应过慢会拖垮整个服务,所以出现了熔断:

熔断器:

  • 请求过大自动熔断,请求超时也会熔断
  • 不正常工作也有自己的默认值,保证服务之间的解耦合

Hystrix是一个延迟和容错库,旨在隔离对远程系统,服务和第三方库的访问点,停止级联故障,并在复杂的分布式系统中实现弹性,在这些系统中,故障是不可避免的。
在这里插入图片描述

简单写一个熔断

public class MyBreaker {
    public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        //sum(1,2);
        Future<Integer> future = threadPool.submit(new Callable<Integer>() {
            public Integer call() throws Exception {
                return sum(1, 2);
            }
        });
        Integer returnValue =null;
        try {
            returnValue =future.get(100, TimeUnit.MILLISECONDS);
        } catch (Exception e){
            returnValue = 0;
        }
        System.out.println(returnValue);

    }
    public static int sum(int x,int y){
        try {
            int seconds=new Random().nextInt(200);
            Thread.sleep(seconds);
            System.out.println("sleep:"+seconds);
        } catch (InterruptedException e) {

        }
        return x+y;
    }
}

熔断器的代码应该放在spring的环绕的通知里面 Spring的AOP,就是代理对象,切面切出来的结果
Hystrix的库被封装到了spring当中
可以加许多地方dao,service都能加

专门要搞Hystrix的话 参考GitHub上的这个案例

https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica
https://github.com/Netflix/Hystrix/wiki/Configuration

如何集成熔断器

pom.xml

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

SpringBootApplication入口中需要添加@EnableCircuitBreaker注解,此时Spring工厂会启动AOP方式对所有的方法上有@HystrixCommand的业务方法添加熔断策略。

@SpringBootApplication
@EnableCircuitBreaker
@MapperScans(value = {@MapperScan(basePackages = {"com.jiangzz.dao"})})
public class HystrixSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixSpringBootApplication.class,args);
    }
}

在业务方法上添加@HystrixCommand注解实现熔断

//HystrixCommand会产生一个代理类
@HystrixCommand//这个也不是spring提供的是Hystrix的
@Override
public Integer sum(Integer a,Integer b) {
    System.out.println(Thread.currentThread().getId());
    return a+b;
}

这个时候你在去测试

//这个时候你去查看你的ThreadID 发现变了
@SpringBootTest(classes = HystrixSpringBootApplication.class)
@RunWith(SpringRunner.class)
public class UserServiceTests {
    @Autowired
    private IUserService userService;
    @Test
    public void testSum(){
        System.out.println("thread:"+Thread.currentThread().getId());
        System.out.println(userService.getClass());
        Integer result = userService.sum(1, 2);
        System.out.println(result);
    }
}

线程隔离

默认该方法的执行会启动新的线程执行和主程序不在一个线程中,因此如果上下文中存在ThreadLocal变量,在该方法中就失效了。因此一般可以通过设置commandProperties注解属性,设置线程就可以了。

//默认的execution.isolation.strategy是thread(做限流必须用这个)但这不能传递ThreadLocal变量
@HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.strategy",value = "SEMAPHORE")
    })
@Override
public Integer sum(Integer a,Integer b) {
    System.out.println(Thread.currentThread().getId());
    return a+b;
}

Fallback

过在@HystrixCommand中声明fallbackMethod的名称可以实现优雅降级(出错的备选方案),如下所示:

@HystrixCommand(fallbackMethod = "fallbackMethodQueryUserById")
@Override
public Integer sum(Integer a,Integer b) {
    System.out.println(Thread.currentThread().getId());
     int i=10/0;
    return (a+b)*2;
}
//注意这个Throwable必须写在后面
public Integer sum(Integer a,Integer b,Throwable e) {
    System.out.println(e.getMessage());
    System.out.println(Thread.currentThread().getId());
    return a+b;
}

注意要求fallbackMethod方法和目标方法必须在同一个类中,具有相同的参数(异常参数可选)

Error Propagation

根据此描述,@ HystrixCommand能够指定应忽略的异常类型。如下所述ArithmeticException: / by zero将不会触发fallbackMethod方法。

//忽略算数异常
@HystrixCommand(fallbackMethod = "fallbackMethodQueryUserById",ignoreExceptions = {ArithmeticException.class})
@Override
public Integer sum(Integer a,Integer b) {
    System.out.println(Thread.currentThread().getId());
     int i=10/0;
    return (a+b)*2;
}
//注意这个Throwable必须写在后面
public Integer sum(Integer a,Integer b,Throwable e) {
    System.out.println(e.getMessage());
    System.out.println(Thread.currentThread().getId());
    return a+b;
}

请求超时熔断

在这里插入图片描述

//默认的execution.isolation.strategy是thread(做限流必须用这个)但这不能传递ThreadLocal变量
@HystrixCommand(commandProperties = {
       @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="100")
    })
@Override
public Integer sum(Integer a,Integer b) {
    System.out.println(Thread.currentThread().getId());
    return a+b;
}

熔断器限流:
断路器:当你每次等100ms才熔断的时候我们可以配置一个次数 如果你连续多少次都熔断了 我就预判你故障了 下次访问的时候我就直接打开你的断路器的开关,每次失败的时候才去熔断然后执行Fallback就慢了。
具体可以参考这个博客:
https://blog.csdn.net/tongtong_use/article/details/78611225

hystrix dashbord(检测)

引入pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
</properties>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>
</parent>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.0.1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

propeties

#开启健康检查的所有端口
management.endpoints.web.exposure.include=*

SpringBoot入口类添加@EnableHystrixDashboard注解如下

@SpringBootApplication
@EnableCircuitBreaker
@EnableHystrixDashboard
public class SpringBootApplicationDemo {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApplicationDemo.class,args);
    }
}

访问的web端口

先访问

在这里插入图片描述

然后访问htttp://ip:port/actuor/hystrix.stream

在这里插入图片描述

错误率达到某个阈值 熔断器就应该打开
全开-半开(看你后面能不能正常返回,如果不能再全开)-全闭

配置窗口的大小 要求时间窗口必须是numbucket的整数倍(像spark一样)不然除不整
metrics.rollingStats.timeInMilliseconds
窗口区间个数(可以推出窗口间隔就是窗口大小/区间个数)
metrics.rollingStats.numBuckets
设置最小请求次数
circuitBreaker.requestVolumeThreshold 默认值为20
设置错误率默认值为50%
circuitBreaker.errorThresholdPercentage
设置下一步是全开还是半开的间隔 默认为5秒 半开->全开|闭合 取决于下次请求是否降级
circuitBreaker.sleepWindowInMilliseconds

除了这个之外还可以配置线程池的参数

设置线程池大小
coreSize 默认值为10
设置队列最大等待请求数 这俩个配置了之后 20个以后你的请求就会被限流 表现为服务就必须降级了
queueSizeRejectionThreshold

@Service
public class UserService implements IUserService {

    public User failback4QueryUserById(Integer id) {
        return new User(-1,"服务降级!");
    }
    @HystrixCommand(
            fallbackMethod = "failback4QueryUserById",
            commandProperties = {
                    @HystrixProperty(name="execution.isolation.strategy",value="THREAD"),
                    @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "1000"),
                    // 时间窗口 必须是 numBuckets的整数倍数
                    @HystrixProperty(name="metrics.rollingStats.timeInMilliseconds",value = "10000"),//设置窗口长度10秒
                    @HystrixProperty(name="metrics.rollingStats.numBuckets",value = "10"),//设置窗口滑动间隔1s

                    //闸刀开启的条件 请求数> 2 && 错误率> 50%
                    @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),//设置最小请求次数
                    @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50"),//设置错误率50%
                    @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),// 当全开到半开的时间间隔
            },
            threadPoolProperties = {
                    @HystrixProperty(name="coreSize",value="10"),//设置线程池大小
                    @HystrixProperty(name="queueSizeRejectionThreshold",value = "10")//设置队列最大等待请求数
            }

    )
    @Override
    public User queryUserById(Integer id) {
        int random = new Random().nextInt(3000);
        try {
            System.out.println("sleep:"+random);
            Thread.sleep(random);
        } catch (InterruptedException e) {

        }
        return new User(id,"user"+id);
    }
}

总结:做好熔断 避免你的服务引起蝴蝶效应

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值