SpringCloud入门实战(6)-Hystrix使用

Hystrix是一个用于分布式系统的延迟和容错的开源库。在分布式系统里,许多依赖不可避免的调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整个服务失败,避免级联故障,以提高分布式系统的弹性。本文主要介绍Hystrix的基本使用,文中使用到的软件版本:Spring Boot 2.2.5.RELEASE、Spring Cloud Hoxton.SR3、Java 1.8.0_191。

1、Hystrix作用

1.1、资源隔离

包括线程池隔离和信号量隔离,限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其他服务调用。

  线程切换 支持异步 支持超时 支持熔断 限流 开销
信号量
线程池

 

 

 

1.2、降级

超时降级、资源不足时(线程或信号量)降级,降级后可以配合降级接口返回托底数据。

1.3、融断

当失败率达到阀值自动触发降级(如因网络故障/超时造成的失败率高),熔断器触发的快速失败会进行快速恢复。

1.4、缓存

提供了请求缓存、请求合并实现。

2、Hystrix处理过程

1.构造一个 HystrixCommand或HystrixObservableCommand对象,用于封装请求,并在构造方法配置请求被执行需要的参数;
2.执行命令,Hystrix提供了4种执行命令的方法;
3.判断是否使用缓存响应请求,若启用了缓存,且缓存可用,直接使用缓存响应请求。Hystrix支持请求缓存,但需要用户自定义启动;
4.判断熔断器是否打开,如果打开,跳到第8步;
5.判断线程池/队列/信号量是否已满,已满则跳到第8步;
6.执行HystrixObservableCommand.construct()或HystrixCommand.run(),如果执行失败或者超时,跳到第8步;否则,跳到第9步;
7.统计熔断器监控指标;
8.走Fallback备用逻辑
9.返回请求响应

3、Hystrix参数说明

配置项默认值说明
hystrix.command.default.execution.isolation.strategy THREAD 隔离策略,THREAD, SEMAPHORE
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 1000 线程超时时间
hystrix.command.default.execution.timeout.enabled true 启用超时设置
hystrix.command.default.execution.isolation.thread.interruptOnTimeout true 线程超时时,是否可被中断
hystrix.command.default.execution.isolation.thread.interruptOnCancel false 线程取消时,是否可被中断
hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests 10 最大并发信号量
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 10 最大并发备用信号量
hystrix.command.default.fallback.enabled true 启用fallback
hystrix.command.default.circuitBreaker.enabled true 启用断路器
hystrix.command.default.circuitBreaker.requestVolumeThreshold 20 在一个时间窗口内触发断路器的最小请求量
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds 5000 触发断路器时,服务休眠时间
hystrix.command.default.circuitBreaker.errorThresholdPercentage 50 触发断路器时,最小错误比率
hystrix.command.default.circuitBreaker.forceOpen false 强制打开断路器
hystrix.command.default.circuitBreaker.forceClosed false 强制关闭断路器
hystrix.command.default.metrics.rollingStats.timeInMilliseconds 10000 数据采集时间段
hystrix.command.default.metrics.rollingStats.numBuckets 10 采集数据份,必须能被timeInMilliseconds整除
hystrix.command.default.metrics.rollingPercentile.enabled true 开启采集滚动百分比
hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds 60000 滚动百分收集时间段
hystrix.command.default.metrics.rollingPercentile.numBuckets 6 滚动百分比收集份数,必须能被timeInMilliseconds整除
hystrix.command.default.metrics.rollingPercentile.bucketSize 100 每份数据的最大统计请求量
hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds 500 健康检查间隔时间
hystrix.command.default.requestCache.enabled true 开启请求缓存,HystrixRequestCache
hystrix.command.default.requestLog.enabled true 开启请求日志,记录在HystrixRequestLog
hystrix.collapser.default.maxRequestsInBatch Integer.MAX_VALUE 单批次最大请求量
hystrix.collapser.default.timerDelayInMilliseconds 10 批次请求延迟启动时间
hystrix.collapser.default.requestCache.enabled true 开启批次请求缓存, HystrixCollapser.execute(), HystrixCollapser.queue()
hystrix.threadpool.default.coreSize 10 核心线程数
hystrix.threadpool.default.maximumSize 10 最大线程数
hystrix.threadpool.default.maxQueueSize -1 最大阻塞线程队列
hystrix.threadpool.default.queueSizeRejectionThreshold 5 队列上限,超过会拒绝请求
hystrix.threadpool.default.keepAliveTimeMinutes 1 线程保持活跃时间(分钟)
hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize false 启用maximumSize参数
hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds 10000 线程池数据采集时间段
hystrix.threadpool.default.metrics.rollingStats.numBuckets 10 线程池数据采集份数

4、使用

4.1、结合springboot使用

4.1.1、引入依赖

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

4.1.2、配置Hystrix(application.yml)

根据需要配置Hystrix,也可以使用默认的配置。参数的意思可以参考上面的参数说明。

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000
      circuitBreaker:
        requestVolumeThreshold: 3

4.1.3、启动类增加@EnableCircuitBreaker(或@EnableHystrix)

package com.abc.scdemo.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

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

4.1.4、编写controller

package com.abc.scdemo.client.controller;

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hystrix")
/**defaultFallback为默认的降级方法,没有参数,返回值要与Hystrix方法的返回值相同*/
@DefaultProperties(commandProperties = {
    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "3"),
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
}, defaultFallback = "defaulFallback")
public class HystrixController {
    private Logger logger = LoggerFactory.getLogger(HystrixController.class);

    @RequestMapping("/test")
    /**fallbackMethod为降级方法,需要与Hystrix方法的签名和返回值一致*/
    @HystrixCommand(
        commandProperties = {
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "3"),
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
        },
        fallbackMethod = "fallback")
    public String test(long id) {
        logger.info(id + "");

        try {
            Thread.sleep(1000 * 5);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "test";
    }

    @RequestMapping("/test2")
    @HystrixCommand()
    public String test2(long id) {
        logger.info(id + "");

        try {
            Thread.sleep(1000 * 5);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "test2";
    }

    public String fallback(long id) {
        logger.info(id + "");
        return "fallback";
    }

    public String defaulFallback() {
        return "defaulFallback";
    }
}

方法上的配置优先级最高,其次是类上的配置,最后时配置文件中的配置。

访问http://localhost:9002/hystrix/test?id=2,前三次会等待3秒,然后返回"fallback";第三次已触发熔断,第四次访问会快速返回"fallback"

访问http://localhost:9002/hystrix/test2?id=2,前三次会等待2秒,然后返回"defaultFallback";第三次已触发熔断,第四次会快速返回"defaultFallback"

4.2、与Feign结合使用

4.2.1、配置启用Hystrix

feign:
  hystrix:
    enabled: true

4.2.2、定义Feign接口

package com.abc.scdemo.client.feign;

import com.abc.scdemo.client.entity.CallResult;
import com.abc.scdemo.client.entity.User;
import com.abc.scdemo.client.feign.fallback.UserFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

//scdemo-server为服务名称
@FeignClient(name = "scdemo-server", fallback = UserFallBack.class)
public interface IUserFeign {
    @PostMapping("/user/addUser")
    CallResult<User> addUser(@RequestBody User user);

    @PostMapping("/user/getUser")
    CallResult<User> getUser(@RequestParam("id") long id);
}

4.2.3、定义降级实现类

package com.abc.scdemo.client.feign.fallback;

import com.abc.scdemo.client.entity.CallResult;
import com.abc.scdemo.client.entity.User;
import com.abc.scdemo.client.feign.IUserFeign;
import org.springframework.stereotype.Component;

@Component
public class UserFallBack implements IUserFeign {
    @Override
    public CallResult<User> addUser(User user) {
        return new CallResult<>(1, "增加用户服务暂不可用!");
    }

    @Override
    public CallResult<User> getUser(long id) {
        return new CallResult<>(1, "获取用户服务暂不可用!");
    }
}

4.2.4、Controller中调用Feign接口

package com.abc.scdemo.client.controller;

import com.abc.scdemo.client.entity.CallResult;
import com.abc.scdemo.client.entity.User;
import com.abc.scdemo.client.feign.IUserFeign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/userfeign")
public class FeignController {
    private Logger logger = LoggerFactory.getLogger(FeignController.class);
    @Autowired
    private IUserFeign userFeign;

    @RequestMapping("/addUser")
    public CallResult<User> addUser(String name, String address) {
        logger.info("name={},address={}", name, address);
        CallResult<User> result = new CallResult<>();
        try {
            User user = new User();
            user.setName(name);
            user.setAddress(address);
            CallResult<User> resultServer = userFeign.addUser(user);
            logger.info("server返回结果:{}" + resultServer);

            User user2 = resultServer.getResult();
            user2.setName("client-" + user2.getName());
            result.setResult(user2);
        } catch (Exception e) {
            result = new CallResult<User>(-1, "发生异常");
            e.printStackTrace();
        }
        return result;
    }

    @RequestMapping("/getUser")
    public CallResult<User> getUser(long id) {
        logger.info(id + "");

        CallResult<User> result = null;
        try {
            result = userFeign.getUser(id);
        } catch (Exception e) {
            result = new CallResult<User>(-1, "发生异常");
            e.printStackTrace();
        }
        return result;
    }
}

当scdemo-server服务不存在或调用超时,都会返回降级实现类中返回的信息。

4.3、与SpringCloud Gateway结合使用

4.3.1、引入依赖

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

4.3.2、编写回退controller

package com.abc.scdemo.gateway.controller;

import com.abc.scdemo.gateway.entity.CallResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FallbackController {
    @RequestMapping("/fallback")
    public CallResult<String> fallback() {
        return new CallResult<>(-10, "服务不可用");
    }
}

4.3.3、配置Hystrix filter

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false #是否开启服务注册和发现功能;将为每一个服务创建一个router,这个router把以服务名开头的请求路径转发到对应的服务上
          lower-case-service-id: true #将请求路径上的服务名转为小写
      routes:
      - id: client
        uri: lb://scdemo-client
        predicates:
        - Path=/scdemo-client/**
        filters:
        - StripPrefix=1 #路由时会去除/scdemo-client
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/fallback

通过网关调用服务时,当scdemo-client服务不存在或调用超时,都会返回降级controller中fallback方法返回的信息。

5、hystrix-dashboard

Hystrix Dashboard是作为断路器状态的一个组件,提供了数据监控和友好的图形化界面,通过Hystrix Dashboard,我们可以在页面上看到服务接口的调用情况。

5.1、dashboard服务(端口9002)

5.1.1、引入依赖

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

5.1.2、启动类增加@EnableHystrixDashboard

5.1.3、控制台

http://localhost:9002/hystrix/

5.2、被监控的服务(端口9001)

5.2.1、引入依赖

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

5.2.2、配置端点

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

5.2.3、查看Hystrix指标流

http://localhost:9001/actuator/hystrix.stream,调用9001上Hystrix保护的接口,会有信息输出:

5.3、dashboard中监控服务

在dashboard的控制台(http://localhost:9002/hystrix/)中输入被监控的服务(http://localhost:9001/actuator/hystrix.stream),点击"Monitor Stream",即可呈现监控的情况:

 

 注:dashboard服务和被监控的服务可以在同一服务里面。

 

posted @ 2020-09-07 11:28  且行且码  阅读(497)  评论(0编辑  收藏  举报