SpringCloud梳理-hystrix断路器

BolunWu

1.Hyxtrix

系统容错工具

hystrix的主要功能:降级熔断

1.1降级

调用远程服务失败(异常、超时、服务不存在),可以通过执行当前服务中的一段代码来向客户端发回响应

降级响应

错误提示
返回缓存数据

快速失败

即使后台服务故障,也要让客户端尽快得到错误提示,而不能让客户端等待

1.2添加降级

1.添加 Hystrix 依赖
2.启动类添加 @EnableCircuitBreaker
3.添加降级代码 在远程调用方法上添加@HystrixCommand(fallbackMethod="降级方法")完成降级方法,返回降级响应.

1.2hystrix 超时

默认1秒超时,执行降级
如果配置了ribbon重试,重试还会继续执行,最终重试结果无效
Hystrix超时 >= Ribbon 总的超时时长

1.3hystrix 熔断

当请求量增大、出现过多错误,hystrix可以和后台服务断开连接(过热保护)
可以避免雪崩效应、故障传播

限流措施

流量过大时造成服务故障,可以断开服务,降低它的流量

在特定条件下会自动触发熔断

10秒内20次请求(必须首先满足)
50%出错,执行降级代码.

半开状态下可以自动恢复.

断路器打开几秒后,进入半开状态,尝试发送请求
如果请求成功自动关闭断路器恢复正常
如果请求失败,再保持打开几秒钟

1.4Hystrix Dashboard

Hystrix监控仪表盘,监控Hystrix降级和熔断的错误信息.

1.4.1 actuator

springboot提供的项目监控工具,提供了多种项目的监控数据.
1.健康状态
2.系统环境
3.beans-spring容器中所有的对象
4.mappings - spring mvc 所有映射的路径
......
hystrix在actuator中,添加了自己的监控数据.

1.4.2添加actuator

1.添加actuator依赖
2.yml配置暴露监控信息
m.e.w.e.i="*" - 暴露所有监控
m.e.w.e.i=["health", "beans", "mappings"]
m.e.w.e.i=bean
3.http://xxxxxxxxx/actuator/

1.5搭建Hystrix Dashboard

1.添加Hystrix Dashboard依赖
2.yml配置配置端口
3.添加@EnableHystrixDashboard注解
4.访问访问 http://xxxxxxx/hystrix在输入框填写要监控的数据路径.

2.代码演示

2.1、ribbon + hystrix 断路器

https://github.com/Netflix/Hystrix/wiki

image

2.2微服务宕机时,ribbon无法转发请求.

关闭item-service

image

image

2.3复制ribbon项目,改名为hytrix

image

2.3.1修改pom.xml文件

image

2.3.2添加hystrix起步依赖

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

2.3.3修改application.yml文件

image


spring:
  application:
    name: hystrix
    
server:
  port: 3001
  
eureka:
  client:    
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  MaxAutoRetries: 1
  MaxAutoRetriesNextServer: 2
  OkToRetryOnAllOperations: true

2.3.4启动类添加@EnableCircuitBreaker注解启用hystrix断路器

启动断路器,断路器提供的两大核心
降级,超时 出错 不可到达时 对服务器降级 返回错误信息或者是缓存数据.
熔断当服务压力过大时 错误比例过多时 熔断有所请求时 所有请求直接降级.
package com.tedu.sp06;

import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

//@EnableCircuitBreaker
//@EnableDiscoveryClient
//@SpringBootApplication

@SpringCloudApplication
public class Sp06RibbonApplication {

    @LoadBalanced
    @Bean
    public RestTemplate getRestTemplate() {
        SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
        f.setConnectTimeout(1000);
        f.setReadTimeout(1000);
        return new RestTemplate(f);
        
        //RestTemplate 中默认的 Factory 实例中,两个超时属性默认是 -1,
        //未启用超时,也不会触发重试
        //return new RestTemplate();
    }

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

}

2.4RibbonController中添加降级方法

为每个方法添加降级方法.
添加@HystrixCommand注解,指定降级方法名
package com.tedu.sp06.consoller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.tedu.sp01.pojo.Item;
import com.tedu.sp01.pojo.Order;
import com.tedu.sp01.pojo.User;
import com.tedu.web.util.JsonResult;

@RestController
public class RibbonController {
    @Autowired
    private RestTemplate rt;
    
    @GetMapping("/item-service/{orderId}")
    @HystrixCommand(fallbackMethod = "getItemsFB") //指定降级方法的方法名
    public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
        return rt.getForObject("http://item-service/{1}", JsonResult.class, orderId);
    }

    @PostMapping("/item-service/decreaseNumber")
    @HystrixCommand(fallbackMethod = "decreaseNumberFB")
    public JsonResult decreaseNumber(@RequestBody List<Item> items) {
        return rt.postForObject("http://item-service/decreaseNumber", items, JsonResult.class);
    }

    /
    
    @GetMapping("/user-service/{userId}")
    @HystrixCommand(fallbackMethod = "getUserFB")
    public JsonResult<User> getUser(@PathVariable Integer userId) {
        return rt.getForObject("http://user-service/{1}", JsonResult.class, userId);
    }

    @GetMapping("/user-service/{userId}/score") 
    @HystrixCommand(fallbackMethod = "addScoreFB")
    public JsonResult addScore(@PathVariable Integer userId, Integer score) {
        return rt.getForObject("http://user-service/{1}/score?score={2}", JsonResult.class, userId, score);
    }
    
    /
    
    @GetMapping("/order-service/{orderId}")
    @HystrixCommand(fallbackMethod = "getOrderFB")
    public JsonResult<Order> getOrder(@PathVariable String orderId) {
        return rt.getForObject("http://order-service/{1}", JsonResult.class, orderId);
    }

    @GetMapping("/order-service")
    @HystrixCommand(fallbackMethod = "addOrderFB")
    public JsonResult addOrder() {
        return rt.getForObject("http://order-service/", JsonResult.class);
    }
    
    /

    //降级方法的参数和返回值,需要和原始方法一致,方法名任意
    public JsonResult<List<Item>> getItemsFB(String orderId) {
        return JsonResult.err("获取订单商品列表失败");
    }
    public JsonResult decreaseNumberFB(List<Item> items) {
        return JsonResult.err("更新商品库存失败");
    }
    public JsonResult<User> getUserFB(Integer userId) {
        return JsonResult.err("获取用户信息失败");
    }
    public JsonResult addScoreFB(Integer userId, Integer score) {
        return JsonResult.err("增加用户积分失败");
    }
    public JsonResult<Order> getOrderFB(String orderId) {
        return JsonResult.err("获取订单失败");
    }
    public JsonResult addOrderFB() {
        return JsonResult.err("添加订单失败");
    }

}

2.5hystrix短路超时设置

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
为了测试hystrix短路功能,我们把hystrix等待超时设置得非常小(500毫秒)
此设置一般应大于ribbon的重试超时时长,例如10秒

spring:
  application:
    name: hystrix
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  MaxAutoRetriesNextServer: 2
  MaxAutoRetries: 1
  OkToRetryOnAllOperations: true
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 500
            

2.6启动项目测试

image

通过hystrix服务,访问可能超时失败的item-service(设置了延迟)

http://localhost:3001/item-service/35

通过hystrix服务,访问未启动的user-service

http://localhost:3001/user-service/7

可以看到,如果item-service请求超时时,hystrix会立即执行降级方法.
访问user-service,由于该服务未启动,hystrix也会立即执行降级方法.

image

3.hystrix dashboard 断路器仪表盘

image

hystrix对请求的熔断和断路处理,可以产生监控信息,提供了各种监控信息的监控端点.
management.endpoints.web.exposure.include 配置选项,可以指定端点名,来暴露监控端点.
如果要暴露全部端点可以用"*"

3.1修改pom.xml文件

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

3.2调整application配置,并暴露hystrix监控端点

spring:
  application:
    name: hystrix
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
ribbon:
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1
  OkToRetryOnAllOperations: true
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000

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

3.3访问actuator路径,查看监控端点

http://localhost:3001/actuator

image

4.新建hystrix-dashboard项目

image

image

4.1修改pom.xml文件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.tedu</groupId>
    <artifactId>sp08-hystrix-dashboard</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sp08-hystrix-dashboard</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <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-dashboard</artifactId>
        </dependency>

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

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>


4.2修改application.yml

spring:
  application:
    name: hystrix-dashboard
    
server:
  port: 4001

eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

4.3修改启动类添加@EnableHystrixDashboard注解和@EnableDiscoveryClient注解

package com.tedu.sp08;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@EnableDiscoveryClient
@EnableHystrixDashboard
@SpringBootApplication
public class Sp08HystrixDashboardApplication {

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

}

4.4启动,访问测试

image

访问hystrix dashboard

http://localhost:4001/hystrix
image

填入hystrix的监控点 开启监控

http://localhost:3001/actuator/hystrix.stream
image

通过hystrix多次访问 观察监控信息

http://localhost:3001/item-service/35

http://localhost:3001/user-service/7

http://localhost:3001/user-service/7/score?score=100

http://localhost:3001/order-service/123abc

http://localhost:3001/order-service/

image

image

4.5hystrix熔断

整个链路达到一定的阀值,默认情况下 10秒内产生超过20次请求,则符合第一个条件.
满足第一个条件的情况下,如果请求的错误百分比大于阈值,则会打开断路器,默认为50%.
hystrix逻辑,先判断是否满足第一个条件,在判断第二个条件,如果两个条件都满足,则会开启断路器.
短路器开启5秒后,会处于半开状态,会尝试转发请求,如果仍然失败,保持打开状态,如果成功,则关闭断路器.

4.6使用apache的并发访问测试工具ab

http://httpd.apache.org/docs/current/platform/windows.html#down
image

使用ab工具,以并发50次,来发送2000个请求.
ab -n 20000 -c 50 http://localhost:3001/item-service/35
断路器状态为Open,所有请求会被短路,直接降级执行fallback方法.

image

4.7hystrix配置

https://github.com/Netflix/Hystrix/wiki/Configuration

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 请求超时时间,超时后触发失败降级.
hystrix.command.default.circuitBreaker.requestVolumeThreshold 10秒内请求数量,默认20,如果没有达到改数量,既使请求全部失败,也不会触发断路器打开.
hystrix.command.default.circuitBreaker.errorThresholdPercentage 失败请求百分比,达到该比例则触发断路器打开.
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds 断路器打开多长时间后,再次允许访问尝试(半开),仍失败则继续保持打开状态,如果成功访问关闭断路器,默认5000.
阅读 611
4 声望
3 粉丝
0 条评论
你知道吗?

4 声望
3 粉丝
宣传栏