Spring Cloud入门实战(四) Hystrix--实现微服务的容错机制

雪崩效应

微服务架构中,系统通常包括多个服务层。微服务之间通过网络进行通信,从而支撑起整个应用系统,因此,服务间的依赖就难免会存在。而每个微服务都不能保证自己时时刻刻百分百可用。当一个微服务挂掉之后,其他微服务调用这个挂掉微服务的都不可用了。把这种基础服务故障导致级联故障的现象称为雪崩效应。

简单点来说就是 C调用B ,B调用A ,然后A出了故障,导致B处于等待状态,然后C也调不到B。这样的级联故障导致整个系统不可用。

解决方案(容错)

要想防止雪崩效应,就要一个强大的容错机制。容错机制一般需要实现以下两点。

  • 为网络请求设置超时:为每个网络请求设置超时时间,超时不再等待,让资源尽快释放。
  • 使用断路器模式:断路器就相当于家里的自动跳闸的。当请求错误失败数较多,或者有大量超时的请求,就会自动停止对该微服务的请求。

使用Hystrix 实现容错

Hystrix是一个实现了超时机制和断路器模式的工具类库。用户隔离访问远程系统、服务或者第三方库,防止连级失败,从而提高系统的可用性和容错性。它主要基于以下几点:

  • 包裹请求:使用HystrixCommand注解包裹对依赖的调用逻辑,每个命令都在独立的线程中执行。
  • 跳闸机制:当某服务的错误率超过了一定的阈值,Hystrix可以自动或者手动跳闸,停止对该服务的访问。
  • 资源隔离:Hystrix为每个历来都维护了一个小型的线程池。如果该线程池已满,发往该依赖的请求就会被拒绝,而不是排队等候。从而加速失败的判定。
  • 监控: Hystrix可以实时的监控运行指标和配置的变化。
  • 回退机制: 当请求失败、超时、被拒绝时,或者当断路器被打开时执行回退的逻辑,回退的逻辑可以自己提供。
  • 自我修复: 断路器打开一段时间后,会自动进入半开状态。

上一节中的Feign项目添加Hystrix依赖

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

然后在启动类上添加@EnableHystrix@EnableCircuitBreaker注解。为项目启用断路器支持。

然后修改UserController 在方法上添加@HystrixCommand注解,表示如果这个接口调用失败之后,就执行fallbackMethod指定的方法。

@RestController
public class UserController {

    @Autowired
    private UserFeignClient userFeignClient;

    @RequestMapping("/user/{id}")
    @HystrixCommand(fallbackMethod = "getUserInfoFallBack")
    public String getUserInfo(@PathVariable Long id){

        return userFeignClient.getUserInfo(id);

    }

    public String getUserInfoFallBack(Long id){

        return "eureka-client 不可用啦!" + id;
    }
}

然后不启动eureka-client。让FeignClient找不到服务地址。访问http://localhost:8004/user/1

发现容错已经实现了。

在这里插入图片描述
但是这时候并不代表断路器打开不会去请求相关服务了,这时候只是执行了回退方法,默认5秒内失败20次打开断路器。

证实:
在pom文件中引入actuator的依赖

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

在yml配置文件中添加配置,显示服务的健康状态。

management:
  endpoint:
    health:
      show-details: always

然后启动服务。访问http://localhost:8004/actuator/health
在这里插入图片描述
可以看到状态还是UP,断路器处于关闭状态下,还是回去请求别的服务。然后试试连续请求20次以上(5s内)。
在这里插入图片描述
可以看到,状态已经是打开了。这样,断路器才是打开状态的。

@HystrixCommand还可以添加一些属性来配置。例如:

    @RequestMapping("/user/{id}")
    @HystrixCommand(fallbackMethod = "getUserInfoFallBack",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000"),
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "5000"),
    },threadPoolProperties = {
            @HystrixProperty(name = "coreSize",value = "1"),
            @HystrixProperty(name = "maxQueueSize",value = "10")
    })
    public String getUserInfo(@PathVariable Long id){

        return userFeignClient.getUserInfo(id);

    }

这些属性的定义可以访问Hystrix官方属性值定义查看。

Hystrix的隔离策略

Hystrix的隔离策略有两种:

  • THREAD(线程隔离):使用该方式,HystrixCommand 将会在单独的线程上执行,并发请求受线程池的线程数量影响。
  • SEMAPHORE(信号量):这种方式。HystrixCommand将会在调用线程上执行,开销相对较少,并发请求受到信号量个数的闲置。

默认是使用 线程隔离 的,因为这种方式有一个除了网络超时以外的额外保护层。
一般来说,只有当负载非常高的时候,才会选用信号量,因为这种场景下,使用线程隔离的开销比较大。信号量一半仅适用于非网络调用的隔离。

可以使用

@HystrixProperty(name = "execution.isolation.straregy",value = "SEMAPHORE")

来指定隔离策略。

在Feign中使用Hystrix

如果想在FeignClient中实现Hystrix怎么做呢。

新建一个FeignClientFallback 类。

@Component
public class FeignClientFallback implements UserFeignClient {

    @Override
    public String getUserInfo(Long id) {
        return "请求失败了!";
    }
}

然后在 UserFeignClient@FeignClient注解上添加fallback = FeignClientFallback.class属性。

在这里插入图片描述
然后在yml配置文件中添加Feign 对 Hystrix的支持。

feign:
  hystrix:
    enabled: true

这样就成了。访问http://localhost:8004/user/1
在这里插入图片描述


检查回退的原因

很多场景下需要检查回退的原因。这就可以使用@FeignClientfallbackFactory属性。

新建一个FeignClientFallbackFactory类。

@Component
public class FeignClientFallbackFactory implements FallbackFactory<UserFeignClient> {

    public static final Logger logger = LoggerFactory.getLogger(FeignClientFallbackFactory.class);

    @Override
    public UserFeignClient create(Throwable cause) {
        return new UserFeignClient() {
            @Override
            public String getUserInfo(Long id) {
                logger.info("fallback !! because:",cause);
                return "请求失败了。。。。。";
            }
        };
    }
}

修改UserFeignClient@FeignClient属性,去掉fallback。加上fallbackFactory
在这里插入图片描述
请求http://localhost:8004/user/1,发现是对的,走的fallbackFactory里的方法。
在这里插入图片描述
查看控制台。
在这里插入图片描述


# Hystrix自带的监控 在启动类加一个方法。
	/**
	 * 低版本(2.0以前)直接启动即可使用 http://ip:port/hystrix.stream 查看监控信息
	 * 高版本(2.0以后)需要添加本方法方可使用 http://ip:port/hystix.stream 查看监控信息
	 *
	 * @return
	 */
	@Bean
	public ServletRegistrationBean getServlet() {
		HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
		ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
		registrationBean.setLoadOnStartup(1);
		registrationBean.addUrlMappings("/hystrix.stream");
		registrationBean.setName("HystrixMetricsStreamServlet");
		return registrationBean;
	}

然后访问http://localhost:8004/hystrix.stream 会发现一直在ping。然后访问一下http://localhost:8004/user/1
可以看到效果了。

在这里插入图片描述

但是这样的数据太难看了。所以接下来说说可视化的监控数据。


Hystrix Dashboard 可视化监控数据

新建一个全新的项目。

pom文件中加入dashboard的依赖。

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

启动类上加上@EnableHystrixDashboard注解。

配置一个端口。

server:
  port: 8005

然后访问 http://localhost:8005/hystrix,可以看到下面的画面。
在这里插入图片描述
在地址栏输入 Hystrix的服务端口和监控数据的地址。下面两个随便填。点击 Monitor Stream
就能看到监控的详情。

在这里插入图片描述
各项指标的属性如图。也可以访问dashboard wiki查看。
在这里插入图片描述
但是这样监控多个就不好了。需要来回切换。


# 使用Turbine 做聚合数据监控 Turbine是一个聚合监控数据的工具,他可以将所有相关的 /hystrix.stream 的数据聚合到一个 /turbine.stream 中。 新建一个项目:pom文件加入Turbine的依赖。
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

yml配置文件如下:

server:
  port: 8007
spring:
  application:
    name: hystrix-turbine


eureka:
  instance:
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://user:123456@server1:8000/eureka/,http://user:123456@server2:8002/eureka/
management:
  endpoints:
    web:
      exposure:
        include: '*'
turbine:
  app-config: ribbon-consumer1,ribbon-consumer2
  cluster-name-expression: "'default'"
  instanceUrlSuffix: hystrix.stream

启动类上添加注解。@EnableTurbine@EnableDiscoveryClient

然后访问 dashboard项目也就是 http://localhost:8005/hystrix
输入 localhost:8007/turbine.stream ,点击
在这里插入图片描述
就能看到监控了多个了。

在这里插入图片描述

使用消息中间件收集数据

安装好一个消息中间件,我安装的是RabbitMQ。
装好之后启动、访问http://localhost:15672/
在这里插入图片描述
修改ribbon-consumer1ribbon-consumer2两个服务。
pom文件中加入

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
			<version>2.2.1.RELEASE</version>
		</dependency>

配置文件中加入:

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

然后改一下 hystrix-turbine,pom文件中加入。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine-stream</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

删除 netflix-turbine依赖,不删除的话,启动会报错。

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

yml文件中同样也添加rabbitmq配置。

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

删除掉下面的配置,不删除也会报错。

turbine:
  app-config: ribbon-consumer1,ribbon-consumer2
  cluster-name-expression: "'default'"
  instanceUrlSuffix: hystrix.stream

启动上的@EnableTurbine注解换成@EnableTurbineStream

然后启动两个ribbon项目,启动eureka-server。启动turbine。访问http://localhost:8007/turbine的端口。

这时候会还是看不到数据。他会一直这样。
在这里插入图片描述
去mq控制台。
在这里插入图片描述
在这里插入图片描述
然后请求一遍原来的服务。再访问http://localhost:8007/。就能看到数据了。
在这里插入图片描述
总结一下,坑挺多的。

发布了41 篇原创文章 · 获赞 9 · 访问量 2525

猜你喜欢

转载自blog.csdn.net/weiwei_six/article/details/103764335