Spring Cloud4 熔断Hystrix的使用

一. 项目spring-cloud-user-service-8081

1. 添加依赖

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

2. 启动类添加注解

@EnableCircuitBreaker // 开启熔断Hystrix

3. 配合控制类使用restTemplate

@Configuration
public class RestTemplateConfiguration {

    @Bean
    public RestTemplate buildRestTemplate(RestTemplateBuilder restTemplateBuilder) {
        System.out.println("====== RestTemplateConfiguration buildRestTemplate ======");
        return restTemplateBuilder.build();
    }
}

4. 测试控制类

@RestController
public class TestHystrixController {

    public final static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private RestTemplate                 restTemplate;

    /**
     * 熔断触发降级 - 请求失败
     *
     * @param num 个数
     * @return 结果
     */
    @HystrixCommand(fallbackMethod = "zswHystrixFallback", commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50") })
    @RequestMapping("/order/{num}")
    public String queryOrder(@PathVariable Integer num) {
        System.out.println("TestHystrixController queryOrder ------ num: " + num + ",  时间: "
                + simpleDateFormat.format(new Date()));

        if (num % 2 == 0) {
            System.out.println("num是偶数 - 不走远程访问 - 不会触发断路器逻辑");
            return "num是偶数 - 不走远程访问 - 不会触发断路器逻辑";
        }

        System.out.println("num是奇数 - 访问远程 - 订单信息服务器8082 - 如果调不通就走断路器");
        return restTemplate.getForObject("http://127.0.0.1:8082/getOrder", String.class);
    }

    /**
     * 熔断触发降级 - 回退方案(降级处理方案)
     *
     * @param num 请求参数
     * @return 结果
     */
    public String zswHystrixFallback(Integer num) {
        // 可以在此做兜底的数据处理,例如从广告服务器上查询最新的广告失败了,可以返回固定的广告信息
        System.out.println("TestHystrixController zswHystrixFallback ------ num: " + num + "  时间: "
                + simpleDateFormat.format(new Date()));
        return "熔断触发降级 - zswHystrixFallback - 回退方案 - 请求失败!!!";
    }

    /**
     * 请求超时 - 触发降级 (默认的timeoutInMilliseconds , 是1000 即 1s, 1秒钟远程连接还未响应就会触发熔断)
     *
     * @param num 个数
     * @return 结果
     */
    @HystrixCommand(fallbackMethod = "zswTimeoutFallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"), })
    @RequestMapping("/queryOrderTimeout/{num}")
    public String queryOrderTimeout(@PathVariable Integer num) {
        System.out.println("TestHystrixController queryOrderTimeout ------ num: " + num + ",  时间: "
                + simpleDateFormat.format(new Date()));

        if (num % 2 == 0) {
            System.out.println("num是偶数 - 不走远程访问 - 不会触发断路器逻辑");
            return "num是偶数 - 不走远程访问 - 不会触发断路器逻辑";
        }

        System.out.println("num是奇数 - 访问远程 - 订单信息服务器8082 - 如果调不通就走断路器");
        return restTemplate.getForObject("http://127.0.0.1:8082/getOrderTimeOut", String.class);
    }

    /**
     * 请求超时触发降级 - 回退方案(降级处理方案)
     *
     * @param num 请求参数
     * @return 结果
     */
    public String zswTimeoutFallback(Integer num) {
        // 可以在此做兜底的数据处理,例如从广告服务器上查询最新的广告失败了,可以返回固定的广告信息
        System.out.println("TestHystrixController zswTimeoutFallback ------ num: " + num + "  时间: "
                + simpleDateFormat.format(new Date()));
        return "请求超时触发降级 - zswTimeoutFallback - 回退方案 - 请求失败!!!";
    }

    /**
     * 信号量隔离实现<br/>
     * 不会使用Hystrix管理的线程池处理请求。使用容器(Tomcat)的线程处理请求逻辑。<br/>
     * 不涉及线程切换,资源调度,上下文的转换等,相对效率高。<br/>
     * 信号量隔离也会启动熔断机制。如果请求并发数超标,则触发熔断,返回fallback数据。<br/>
     * commandProperties - 命令配置,HystrixPropertiesManager中的常量或字符串来配置。<br/>
     * execution.isolation.strategy - 隔离的种类,<br/>
     * 隔离的种类可选值只有THREAD(线程池隔离)和 SEMAPHORE(信号量隔离)。默认是THREAD线程池隔离。 <br/>
     * 设置信号量隔离后,线程池相关配置失效。<br/>
     * execution.isolation.semaphore.maxConcurrentRequests - 信号量最大并发数。<br/>
     * 信号量最大并发数默认值是10; 常见配置500~1000。 <br/>
     * 如果并发请求超过配置,其他请求进入fallback逻辑。
     */
    @HystrixCommand(fallbackMethod = "semaphoreQuarantineFallback", commandProperties = {
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"), // 信号量隔离
            @HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "100") }) // 信号量最大并发数
    @RequestMapping("/queryOrderBySemaphore/{num}")
    public String queryOrderSemaphore(@PathVariable Integer num) {
        System.out.println("TestHystrixController queryOrderSemaphore ------ num: " + num + ",  时间: "
                + simpleDateFormat.format(new Date()));

        if (num % 2 == 0) {
            System.out.println("num是偶数 - 不走远程访问 - 不会触发断路器逻辑");
            return "num是偶数 - 不走远程访问 - 不会触发断路器逻辑";
        }

        System.out.println("num是奇数 - 访问远程 - 订单信息服务器8082 - 如果调不通就走断路器");
        return restTemplate.getForObject("http://127.0.0.1:8082/getOrder", String.class);
    }

    /**
     * 信号量隔离触发降级 - 回退方案(降级处理方案)
     *
     * @param num 请求参数
     * @return 结果
     */
    public String semaphoreQuarantineFallback(Integer num) {
        // 可以在此做兜底的数据处理,例如从广告服务器上查询最新的广告失败了,可以返回固定的广告信息
        System.out.println("TestHystrixController semaphoreQuarantineFallback ------ num: " + num + "  时间: "
                + simpleDateFormat.format(new Date()));
        return "信号量隔离触发降级 - semaphoreQuarantineFallback - 回退方案 - 请求失败!!!";
    }

    /**
     * 线程池隔离 - 触发降级
     *
     * @param num 个数
     * @return 结果
     */
    @HystrixCommand(groupKey = "order-service", commandKey = "queryOrderByThreadPool", threadPoolKey = "order-service", threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "30"), //线程池大小
            @HystrixProperty(name = "maxQueueSize", value = "100"), //最大队列长度
            @HystrixProperty(name = "keepAliveTimeMinutes", value = "2"), //线程存活时间
            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "15")//拒绝请求
    }, fallbackMethod = "fallbackByThreadPool")
    @RequestMapping("/queryOrderByThreadPool/{num}")
    public String queryOrderByThreadPool(@PathVariable Integer num) {
        System.out.println("TestHystrixController queryOrderByThreadPool ------ num: " + num + ",  时间: "
                + simpleDateFormat.format(new Date()));

        if (num % 2 == 0) {
            System.out.println("num是偶数 - 不走远程访问 - 不会触发断路器逻辑");
            return "num是偶数 - 不走远程访问 - 不会触发断路器逻辑";
        }

        System.out.println("num是奇数 - 访问远程 - 订单信息服务器8082 - 如果调不通就走断路器");
        return restTemplate.getForObject("http://127.0.0.1:8082/getOrder", String.class);
    }

    /**
     * 线程池隔离触发降级 - 回退方案(降级处理方案)
     *
     * @param num 请求参数
     * @return 结果
     */
    public String fallbackByThreadPool(Integer num) {
        // 可以在此做兜底的数据处理,例如从广告服务器上查询最新的广告失败了,可以返回固定的广告信息
        System.out.println("TestHystrixController fallbackByThreadPool ------ num: " + num + "  时间: "
                + simpleDateFormat.format(new Date()));
        return "信号量隔离触发降级 - fallbackByThreadPool - 回退方案 - 请求失败!!!";
    }

}

5. 启动注册中心项目,启动配置中心项目,启动user-service-8081项目,不启动order-service-8082项目,测试结果

6. 熔断状态: Closed(默认关闭), Open(失败超过阈值开启), Half-Open(自重试)

请求发起时:默认10s内20次请求,失败率超过errorThresholdPercentage设置的50%,熔断触发降级,熔断状态改为Open,

熔断开启不再走远程访问,熔断时间为sleepWindowInMilliseconds设置的5s,

从熔断开启的5s内不再发起远程连接,5s之后将熔断开关置于Half-Open状态,

再次进来请求:

若请求成功则熔断开关恢复为Closed;

若请求失败则熔断开关恢复为Open,熔断开关未Open就不能发起远程访问;

5s之后,熔断开关自动恢复为Closed,开始新一轮的统计计算;

二. Hystrix + Feign的使用

1. order-api项目修改OrderServiceFeignClient并重新打包发布到本地仓库

@FeignClient(value = "order-service", fallback = OrderServiceFeignClient.OrderServiceFeignClientFallback.class)
public interface OrderServiceFeignClient extends OrderService {

    @Component
    class OrderServiceFeignClientFallback implements OrderServiceFeignClient {
        public final static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        @Override
        public String findAllList() {
            System.out.println("OrderServiceFeignClient OrderServiceFeignClientFallback findAllList ,  时间: "
                    + simpleDateFormat.format(new Date()));
            return "OrderServiceFeignClientFallback - findAllList - 熔断失败";
        }

        @Override
        public String findById() {
            System.out.println("OrderServiceFeignClient OrderServiceFeignClientFallback findById ,  时间: "
                    + simpleDateFormat.format(new Date()));
            return "OrderServiceFeignClientFallback - findById - 熔断失败";
        }

        @Override
        public int insertMessage(OrderDto orderDto) {
            System.out.println("OrderServiceFeignClient OrderServiceFeignClientFallback insertMessage ,  时间: "
                    + simpleDateFormat.format(new Date()));
            return -1;
        }
    }
}

2. spring-cloud-user-service-8081项目添加依赖

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

        <dependency>
            <groupId>com.zsw</groupId>
            <artifactId>order-service-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

3.  spring-cloud-user-service-8081项目添加配置

# feign使用熔断机制保护
feign:
  hystrix:
    enabled: true

4. spring-cloud-user-service-8081项目启动类加配置

@ComponentScan(basePackages = { "com.zsw.userserviceprovider", "com.zsw.openfeign.client" }) // openFeign客户端放在了服务提供方,需要扫描到交给spring管理
@EnableFeignClients(basePackages = "com.zsw.openfeign.client") // openFeign客户端

5. spring-cloud-user-service-8081项目测试控制类

@RestController
public class HystrixOpenFeignController {

    @Autowired
    private OrderServiceFeignClient      orderServiceFeignClient;

    public final static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @RequestMapping("/findAllOrderList/{num}")
    public String queryOrderSemaphore(@PathVariable Integer num) {
        System.out.println("HystrixOpenFeignController queryOrderSemaphore ------ num: " + num + ",  时间: "
                + simpleDateFormat.format(new Date()));

        if (num % 2 == 0) {
            System.out.println("num是偶数 - 不走远程访问 - 不会触发断路器逻辑");
            return "num是偶数 - 不走远程访问 - 不会触发断路器逻辑";
        }

        System.out.println("num是奇数 - 访问远程 - 订单信息服务器8082 - 如果调不通就走断路器");
        return orderServiceFeignClient.findAllList();
    }
}

6. 测试

三. Hystrix + DashBoard 使用

1. 新建项目spring-cloud-hystrix-dashboard-9092

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>com.zsw</groupId>
		<artifactId>spring-cloud-1002</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

	<artifactId>spring-cloud-hystrix-dashboard-9092</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-cloud-hystrix-dashboard-9092</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

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

</project>
spring:
  application:
    # 应用名称,
    name: hystrix-dashboard-9092


# 应用服务 WEB 访问端口
server:
  port: 9092
@EnableHystrixDashboard // 开启hystrix监控平台
@SpringBootApplication
public class SpringCloudHystrixDashboard9092Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudHystrixDashboard9092Application.class, args);
    }
}

2. spring-cloud-user-service-8081项目配置新增(hystrix.stream)

# actuator配置
management:
  endpoints:
    # 开启actuator
    enabled-by-default: true
    web:
      exposure:
        # 开启: 提供refresh端点,可以使用接口主动刷新配置中心的配置文件内容
        # 开启refresh刷新配置中心的配置信息, 开启hystrix监控面板
        include: refresh,hystrix.stream

3. dashboard项目启动测试

4. 测试监控接口http://127.0.0.1:8081/findAllOrderList

5. 结果可能报错,原因: springboot版本问题 (我的没有报错哈)

访问http://127.0.0.1:8081/actuator/hystrix.stream正常,可以看见user-service项目不断的ping获取信息

6. 解决方法: spring-cloud-user-service-8081项目加个配置类

@Configuration
public class ZswHystrixConfiguration {

    @Bean
    public ServletRegistrationBean getBean() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet, "/hystrix.stream");
        registrationBean.setLoadOnStartup(1);
        //        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

7. 正常的监控面板

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值