微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SpringCloud-2-基础组件

目录

1 服务调用Feign入门

1.1 Feign简介

1.2 基于Feign的服务调用

1.3 Feign和Ribbon的联系

1.4 负载均衡

2 服务调用Feign高级

2.1 Feign的配置

2.2 请求压缩

2.3 日志级别

2.4 源码分析

3 服务注册与发现总结

3.1 组件的使用方式

3.1.1 注册中心

3.1.2 服务调用

4 微服务架构的高并发问题

4.1 性能工具Jmetter

4.1.1 安装Jmetter

4.1.2 配置Jmetter

4.2 系统负载过高存在的问题

4.2.1 问题分析

4.2.2 线程池的形式实现服务隔离

5 服务熔断Hystrix入门

5.1 服务容错的核心知识

5.1.1 雪崩效应

5.1.2 服务隔离

5.1.3 熔断降级

5.1.4 服务限流

5.2 Hystrix介绍

5.3 Rest实现服务熔断

5.4 Feign实现服务熔断

6 服务熔断Hystrix高级

6.1 Hystrix的监控平台

6.1.1 搭建Hystrix DashBoard监控

​编辑

6.1.2断路器聚合监控Turbine

6.2 熔断器的状态

6.3 熔断器的隔离策略

7 服务熔断Hystrix的替换方案

7.1 替换方案介绍

7.2 Sentinel概述

7.2.1 Sentinel简介

7.2.2 Sentinel与Hystrix的区别Sentinel

7.2.3 迁移方案

7.2.4 名词解释

7.3 Sentinel中的管理控制台

7.3.1 下载启动控制台

7.3.2 客户端能接入控制台

7.3.3 查看机器列表以及健康情况

7.4 基于Sentinel的服务保护

7.4.2 Rest实现熔断

7.4.3 Feign实现熔断


1 服务调用Feign入门

前面我们使用的 RestTemplate 实现 RESTAPI 调用代码大致如下:
@GetMapping("/buy/{id}")
public Product order() {
   Product product = restTemplate.getForObject("http://shop-service-product/product/1",Product.class);
   return product;
}
代码可知,我们是使用拼接字符串的方式构造 URL 的,该 URL 只有一个参数。但是,在现实中, URL中往往含有多个参数。这时候我们如果还用这种方式构造URL ,那么就会非常痛苦。那应该如何解决

1.1 Feign简介

Feign Netflix 开发的声明式,模板化的 HTTP 客户端,其灵感来自 Retrofit,JAXRS-2.0 以及 WebSocket。
  • Feign可帮助我们更加便捷,优雅的调用HTTP API
  • SpringCloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。
  • Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
  • SpringCloudFeign进行了增强,使Feign支持SpringMVC注解,并整合了RibbonEureka,从而让Feign的使用更加方便。

1.2 基于Feign的服务调用

1 )引入依赖
在服务消费者 shop_service_order 添加 Fegin 依赖。
        <!--springcloud整合的openFeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
2 )启动类添加 Feign 支持
通过 @EnableFeignClients 注解开启 Spring Cloud Feign 支持功能
@SpringBootApplication
@EntityScan("cn.awen.order.entity")
//激活Feign
@EnableFeignClients
public class OrderApplication {

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

3)启动类激活FeignClient

创建一个 Feign 接口,此接口是在 Feign 调用微服务的核心接口。在服务消费者 shop_service_order 添加一个 ProductFeginClient 接口定义各参数绑定时,@PathVariable @RequestParam @RequestHeader 等可以指定参数属性,在Feign 中绑定参数必须通过 value 属性来指明具体的参数名,不然会抛出异常。
@FeignClient:注解通过 name 指定需要调用的微服务的名称,用于创建 Ribbon 负载均衡器。 所以Ribbon 会把 shop - service - product 解析为注册中心的服务。
/**
 * 声明需要调用的微服务名称
 *  @FeignClient
 *      * name : 服务提供者的名称
 */
@FeignClient(name="service-product")
public interface ProductFeignClient {

	/**
	 * 配置需要调用的微服务接口
	 */
	@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable("id") Long id);
}

4)配置请求提供者的调用接口

修改 OrderController 添加 ProductFeginClient 自动注入,并在 order 方法中使用ProductFeginClient 完成微服务调用
@RestController
@RequestMapping("/order")
public class OrderController {

	@Autowired
	private ProductFeignClient productFeignClient;
	/**
	 */
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		Product product = null;
		product = productFeignClient.findById(id);
		return product;
	}
}
5 )测试效果

1.3 FeignRibbon的联系

  • Ribbon一个基于HTTPTCP客户端负载均衡的工具。它可以在客户端配置RibbonServerList(服务端列表),使用 HttpClient RestTemplate 模拟http请求,步骤相当繁琐。
  • Feign是在Ribbon的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。采用接口的方式,只需要创建一个接口,然后在上面添加注解即可,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。然后就像是调用自身工程的方法调用,而感觉不到是调用远程方法,使得编写客户端变得非常容易。

1.4 负载均衡

Feign 中本身已经集成了 Ribbon 依赖和自动配置,因此我们不需要额外引入依赖,也不需要再注册RestTemplate 对象。另外,我们可以像上节课中讲的那样去配置 Ribbon ,可以通过 ribbon.xx 来进行全局配置。也可以通过 服务名 .ribbon.xx 来对指定服务配置。

2 服务调用Feign高级

2.1 Feign的配置

Spring Cloud Edgware 开始, Feign 支持使用属性自定义 Feign 。对于一个指定名称 FeignClient(例如该 Feign Client 名称 feignName ), Feign 支持如下配置项:
  • feignNameFeginClient名称
  • connectTimeout : 建立链接的超时时长
  • readTimeout : 读取超时时长
  • loggerLevel: Fegin的日志级别
  • errorDecoder Feign错误解码器
  • retryer : 配置重试
  • requestInterceptors 添加请求拦截
  • decode404 : 配置熔断不处理404异常

2.2 请求压缩

Spring Cloud Feign 支持对请求和响应进行 GZIP 压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能 同时,我们也可以对请求的数据类型,以及触发压缩的大小下限进行设置,且上面的数据类型、压缩大小下限均为认值。
feign: 
    compression: 
        request: enabled: true # 开启请求压缩 
            mime-types: text/html,application/xml,application/json # 设置压缩的数据类型 
            min-request-size: 2048 # 设置触发压缩的大小下限
        response: enabled: true # 开启响应压缩

2.3 日志级别

在开发或者运行阶段往往希望看到 Feign 请求过程的日志记录,认情况下 Feign 的日志是没有开启的。要想用属性配置方式来达到日志效果,只需在 application.yml 添加如下内容即可。
日志级别:
  • NONE性能最佳,适用于生产】:不记录任何日志(认值)
  • BASIC【适用于生产环境追踪问题】:仅记录请求方法URL、响应状态代码以及执行时间
  • HEADERS:记录BASIC级别的基础上,记录请求和响应的header
  • FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的headerbody和元数据。
#配置feign日志的输出
#日志配置  NONE : 不输出日志(高)   BASIC: 适用于生产环境追踪问题
#HEADERS : 在BASIC的基础上,记录请求和响应头信息   FULL : 记录所有
feign:
  client:
    config:
      service-product:  #需要调用的服务名称
        loggerLevel: FULL
logging:
  level:
    cn.itcast.order.feign.ProductFeignClient: debug

2.4 源码分析

通过上面的使用过程, @EnableFeignClients @FeignClient 两个注解就实现了 Feign 功能,那我们从@EnableFeignClients注解开始分析 Feign 的源码。

1 EnableFeignClients 注解
2 FeignClientsRegistrar 注册
3 注册 FeignClient 对象
4 FeignClientfactorybean
5 发送请求

3 服务注册与发现总结

3.1 组件的使用方式

3.1.1 注册中心

1 Eureka
搭建注册中心
  • 引入依赖 spring-cloud-starter-netflix-eureka-server
  • 配置EurekaServer
  • 通过 @EnableEurekaServer 激活Eureka Server端配置
服务注册
  • 服务提供者引入 spring-cloud-starter-netflix-eureka-client 依赖
  • 通过 eureka.client.serviceUrl.defaultZone 配置注册中心地址
2 consul
搭建注册中心
  • 下载安装consul
  • 启动consul consul agent -dev
服务注册
  • 服务提供者引入 spring-cloud-starter-consul-discovery 依赖
  • 通过 spring.cloud.consul.host spring.cloud.consul.port 指定Consul Server的请求地址

3.1.2 服务调用

1 Ribbon
通过 Ribbon 结合 RestTemplate 方式进行服务调用只需要在声明 RestTemplate 方法添加注解@LoadBalanced即可。可以通过 { 服务名称 }.ribbon.NFLoadBalancerRuleClassName 配置负载均衡策略。
2 Feign
服务消费者引入 spring - cloud - starter - openfeign 依赖通过 @FeignClient 声明一个调用远程微服务接口。启动类上通过 @EnableFeignClients 激活 Feign。

4 微服务架构的高并发问题

通过注册中心已经实现了微服务的服务注册和服务发现,并且通过 Ribbon 实现了负载均衡,已经借助Feign可以优雅的进行微服务调用。那么我们编写的微服务的性能怎么样呢,是否存在问题呢?

4.1 性能工具Jmetter

Apache JMeter Apache 组织开发的基于 Java 的压力测试工具。用于对软件做压力测试,它最初被设计用于Web 应用测试,但后来扩展到其他测试领域。 它可以用于测试静态和动态资源,例如静态文件、Java 小服务程序、 CGI 脚本、 Java 对象、数据库 FTP 服务器等等。JMeter 可以用于对服务器、网络或对象模拟巨大的负载,来自不同压力类别下测试它们的强度和分析整体性能。另外JMeter 能够对应用程序做功能/ 回归测试,通过创建带有断言的脚本来验证你的程序返回了你期望的结果。为了最大限度的灵活性,JMeter 允许使用正则表达式创建断言。

4.1.1 安装Jmetter

Jmetter 安装十分简单,使用资料中的 apache - jmeter - 2.13.zip 完整压缩包,解压找到安装目录下bin/jmeter.bat 已管理员身份启动即可

4.1.2 配置Jmetter

1 )创建新的测试计划
2 )测试计划下创建发起请求的线程组
  • 可以配置请求的线程数
  • 以及每个请求发送的请求次数
3 )创建 http 请求模板
4 )配置测试的接口信息

4.2 系统负载过高存在的问题

4.2.1 问题分析

在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,由于网络原因或者自身的原因,服务并不能保证服务的100% 可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务累计,导致服务瘫痪。在SpringBoot 程序中,认使用内置 tomcat 作为 web 服务器。单 tomcat 支持最大的并发请求是有限的,如果某一接口阻塞,待执行的任务积压越来越多,那么势必会影响其他接口的调用

4.2.2 线程池的形式实现服务隔离

1
配置坐标
为了方便实现线以线程池的形式完成资源隔离,需要引入如下依赖
        <!--hystrix-->
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-metrics-event-stream</artifactId>
            <version>1.5.12</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
            <version>1.5.12</version>
        </dependency>

2配置线程池

配置 HystrixCommand 接口的实现类,再实现类中可以对线程池进行配置。
package cn.itcast.order.command;

import cn.itcast.order.entity.Product;
import com.netflix.hystrix.*;
import org.springframework.web.client.RestTemplate;

public class OrderCommand extends HystrixCommand<Product> {

	private RestTemplate restTemplate;
	
	private Long id;

	public OrderCommand(RestTemplate restTemplate, Long id) {
		super(setter());
		this.restTemplate = restTemplate;
		this.id = id;
	}

	private static Setter setter() {

		// 服务分组
		HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("order_product");
		// 服务标识
		HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("product");
		// 线程池名称
		HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("order_product_pool");
		/**
		 * 线程池配置
		 *     withCoreSize :  线程池大小为10
		 *     withKeepAliveTimeMinutes:  线程存活时间15秒
		 *     withQueueSizeRejectionThreshold  :队列等待的阈值为100,超过100执行拒绝策略
		 */
		HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(50)
				.withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);

		// 命令属性配置Hystrix 开启超时
		HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
				// 采用线程池方式实现服务隔离
				.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
				// 禁止
				.withExecutionTimeoutEnabled(false);
		return Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
				.andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);

	}

	@Override
	protected Product run() throws Exception {
		System.out.println(Thread.currentThread().getName());
		return restTemplate.getForObject("http://127.0.0.1/product/"+id, Product.class);
	}

	/**
	 * 降级方法
	 */
	@Override
	protected Product getFallback(){
		Product product = new Product();
		product.setProductName("不好意思,出错了");
		return product;
	}
}
3 配置调用
修改 OrderController ,使用自定义 OrderCommand 完成调用
	/**
	 * 使用OrderCommand调用远程服务
	 */
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		return new OrderCommand(restTemplate,id).execute();
	}

5 服务熔断Hystrix入门

5.1 服务容错的核心知识

5.1.1 雪崩效应

在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问 A 服务,而 A 服务需要调用 B服务,B 服务需要调用 C 服务,由于网络原因或者自身的原因,如果 B 服务或者 C 服务不能及时响应, A 服务将处于阻塞状态,直到B 服务 C 服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“ 雪崩 效应。
雪崩是系统中的蝴蝶效应导致其发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。源头上我们无法完全杜绝雪崩源头的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估,做好熔断,隔离,限流。

5.1.2 服务隔离

顾名思义,它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体的系统服务。

5.1.3 熔断降级

熔断这一概念来源于电子工程中的断路器( Circuit Breaker )。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。 也可以理解为兜底。

5.1.4 服务限流

限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。一般来说系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。比方:推迟解决,拒绝解决,或者者部分拒绝解决等等。

5.2 Hystrix介绍

Hystrix 是由 Netflflix 开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix 主要通过以下几点实现延迟和容错。
  • 包裹请求:使用HystrixCommand包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用了设计模式中的“命令模式
  • 跳闸机制:当某服务的错误率超过一定的阈值时,Hystrix可以自动或手动跳闸,停止请求该服务一段时间。
  • 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
  • 监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
  • 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员自行提供,例如返回一个缺省值。
  • 自我修复:断路器打开一段时间后,会自动进入半开状态。

5.3 Rest实现服务熔断

1 )复制 shop_service_order 项目并命名为 shop_service_order_rest_hystrix
2 )配置依赖
shop_service_order_rest_hystrix 工程中添加 Hystrix 的相关依赖
        <!--引入hystrix依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
3 )开启熔断
在启动类 OrderApplication 添加 @EnableCircuitBreaker 注解开启对熔断器的支持
@SpringBootApplication
//激活hystrix
@EnableCircuitBreaker
@EntityScan("cn.itcast.order.entity")
public class RestOrderApplication {

	@LoadBalanced
	@Bean
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}

	public static void main(String[] args) {
		SpringApplication.run(RestOrderApplication.class,args);
	}
}
4 配置熔断降级业务逻辑
代码可知,为 findProduct 方法编写一个回退方法 fifindProductFallBack ,该方法 findProduct 方法具有相同的参数与返回值类型,该方法返回一个认的错误信息。在 Product 方法上,使用注解 @HystrixCommand fallbackMethod 属性,指定熔断触发的降级方法是 findProductFallBack
  • 因为熔断的降级逻辑方法必须跟正常逻辑方法保证:相同的参数列表和返回值声明
  • findProduct 方法HystrixCommand(fallbackMethod = "findProductFallBack") 用来声明一个降级逻辑的方法
shop - service - product 微服务正常时,浏览器访问 http://localhost:9001/order/product/1 可以正常调用服务提供者获取数据。当将商品微服务停止时继续访问此时Hystrix 配置已经生效进入熔断降级方法
@RestController
@RequestMapping("/order")
/**
 * @DefaultProperties : 指定此接口中公共的熔断设置
 *      如果过在@DefaultProperties指定了公共的降级方法
 *      在@HystrixCommand不需要单独指定了
 */
//@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {

	@Autowired
	private RestTemplate restTemplate;
	
	/**
	 * 使用注解配置熔断保护
	 *     fallbackmethod : 配置熔断之后的降级方法
	 */
	@HystrixCommand(fallbackMethod = "orderFallBack")
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		if(id != 1) {
			throw  new  RuntimeException("服务器异常");
		}
		return restTemplate.getForObject("http://service-product/product/1",Product.class);
	}

	/**
	 * 降级方法
	 *  和需要收到保护的方法的返回值一致
	 *  方法参数一致
	 */
	public Product orderFallBack(Long id) {
		Product product = new Product();
		product.setProductName("触发降级方法");
		return product;
	}

}
认的 Fallback
我们刚才把 fallback 写在了某个业务方法上,如果这样的方法很多,那岂不是要写很多。所以我们可以把Fallback 配置加在类上,实现 fallback。
@RestController
@RequestMapping("/order")
/**
 * @DefaultProperties : 指定此接口中公共的熔断设置
 *      如果过在@DefaultProperties指定了公共的降级方法
 *      在@HystrixCommand不需要单独指定了
 */
//@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {

	@Autowired
	private RestTemplate restTemplate;

	/**
	 * 使用注解配置熔断保护
	 *     fallbackmethod : 配置熔断之后的降级方法
	 */
	@HystrixCommand(fallbackMethod = "orderFallBack")
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		if(id != 1) {
			throw  new  RuntimeException("服务器异常");
		}
		return restTemplate.getForObject("http://service-product/product/1",Product.class);
	}

	/**
	 * 指定统一的降级方法
	 *  * 参数 : 没有参数
	 */
	public Product defaultFallBack() {
		Product product = new Product();
		product.setProductName("触发统一的降级方法");
		return product;
	}

}
超时设置
在之前的案例中,请求在超过 1 秒后都会返回错误信息,这是因为 Hystix 认超时时长为 1 ,我们可以通过配置修改这个值:
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000 #认的连接超时时间1秒,若1秒没有返回数据,自动的触发降级逻辑

5.4 Feign实现服务熔断

SpringCloud Fegin 认已为 Feign 整合了 hystrix ,所以添加 Feign 依赖后就不用在添加 hystrix ,那么怎么才能让Feign 的熔断机制生效呢,只要按以下步骤开发:
1 配置依赖
shop_service_order_rest_hystrix 工程中添加 Hystrix 的相关依赖。
        <!--引入hystrix依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
2 修改 application.yml Fegin 中开启 hystrix
Feign 中已经内置了 hystrix ,但是认是关闭的需要在工程的 application.yml 中开启对 hystrix 支持
feign:
  #开启对hystrix的支持
  hystrix:
    enabled: true
3 )配置 FeignClient 接口的实现类
基于 Feign 实现熔断降级,那么降级方法需要配置到 FeignClient 接口的实现类中。
@Component
public class ProductFeignClientCallBack implements ProductFeignClient {

	/**
	 * 熔断降级的方法
	 */
	public Product findById(Long id) {
		Product product = new Product();
		product.setProductName("feign调用触发熔断降级方法");
		return product;
	}
}
4 修改 FeignClient 添加 hystrix 熔断
@FeignClient注解中添加降级方法。@FeignClient注解中以 fallback 声明降级方法
/**
 * 声明需要调用的微服务名称
 *  @FeignClient
 *      * name : 服务提供者的名称
 *      * fallback : 配置熔断发生降级方法
 *                  实现类
 */
@FeignClient(name="service-product",fallback = ProductFeignClientCallBack.class)
public interface ProductFeignClient {

	/**
	 * 配置需要调用的微服务接口
	 */
	@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable("id") Long id);
}

6 服务熔断Hystrix高级

我们知道,当请求失败,被拒绝,超时的时候,都会进入到降级方法中。但进入降级方法并不意味着断路器已经被打开。那么如何才能了解断路器中的状态呢?

6.1 Hystrix的监控平台

除了实现容错功能 Hystrix 还提供了近乎实时的监控, HystrixCommand 和HystrixObservableCommand在执行时,会生成执行结果和运行指标。比如每秒的请求数量,成功数量等。这些状态会暴露在Actuator 提供的 /health 端点中。只需为项目添加 spring - boot - actuator 依赖,重启项目,访问 http://localhost:9001/actuator/hystrix.stream , 即可看到实时的监控数据。
1 )导入依赖
        <!--引入hystrix的监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
2 )在启动类使用@EnableHystrixDashboard 注解激活仪表盘项目
//激活hystrix
@EnableCircuitBreaker
3 )暴露所有actuator监控的端点
#暴露所有端点
management:
  endpoints:
    web:
      exposure:
        include: '*'

6.1.1 搭建Hystrix DashBoard监控

刚刚讨论了 Hystrix 的监控,但访问 /hystrix.stream 接口获取的都是已文字形式展示的信息。很难通过文字直观的展示系统的运行状态,所以Hystrix 官方还提供了基于图形化的 DashBoard (仪表板)监控平台。Hystrix 仪表板可以显示每个断路器(被 @HystrixCommand 注解的方法)的状态。
1 )导入依赖
        <!--引入hystrix的监控信息-->
        <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>
2 )在启动类使用@EnableHystrixDashboard 注解激活仪表盘项目
//激活hystrix
@EnableCircuitBreaker
//激活hytrix的web监控平台
@EnableHystrixDashboard
3 )访问测试
localhost:9003/hytrix

6.1.2断路器聚合监控turbine

在微服务架构体系中,每个服务都需要配置 Hystrix DashBoard 监控。如果每次只能查看单个实例的监控数据,就需要不断切换监控地址,这显然很不方便。要想看这个系统的Hystrix Dashboard 数据就需
要用到 Hystrix turbine turbine 一个聚合 Hystrix 监控数据的工具,他可以将所有相关微服务的
Hystrix 监控数据聚合到一起,方便使用。引入 turbine 后,整个监控系统架构如下:
1 )搭建turbineServer
创建工程 shop_hystrix_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-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
2 )配置多个微服务的hystrix 监控
application.yml 配置文件中开启 turbine 并进行相关配置
eureka 相关配置 :
  • 指定注册中心地址
  • turbine相关配置:指定需要监控的微服务列表
turbine 自动的从注册中心中获取需要监控的微服务,并聚合所有微服务中的 /hystrix.stream 数据。
server:
  port: 8031
spring:
  application:
    name: hystrix-turbine
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
  instance:
    prefer-ip-address: true
turbine:
  # 要监控的微服务列表,多个用,分隔
  appConfig: service-order
  clusterNameExpression: "'default'"
3 )配置启动类
作为一个独立的监控项目,需要配置启动类,开启 HystrixDashboard 监控平台,并激活 turbine
@SpringBootApplication
//trubin配置
@Enableturbine
@EnableHystrixDashboard
public class TurbinAppliation {

	public static void main(String[] args) {
		SpringApplication.run(TurbinAppliation.class,args);
	}
}
4 )测试
浏览器访问 http://localhost:8031/hystrix 展示 HystrixDashboard 。并在 url 位置输入 http://localhost:8031/turbine.stream ,动态根据 turbine.stream 数据展示多个微服务的监控数据

6.2 熔断器的状态

熔断器有三个状态 CLOSED OPEN HALF_OPEN 熔断器关闭状态,当触发熔断后状态变更为OPEN , 在等待到指定的时间, Hystrix 会放请求检测服务是否开启,这期间熔断器会变为 HALF_OPEN 半开启状态,熔断探测服务可用则继续变更为 CLOSED 关闭熔断器。
  • Closed关闭状态(断路器关闭),所有请求都正常访问。代理类维护了最近调用失败的次数,如果某次调用失败,则使失败次数加1。如果最近失败次数超过了在给定时间内允许失败的阈值,则代理类切换到断开(Open)状态。此时代理开启了一个超时时钟,当该时钟超过了该时间,则切换到半断开(Half-Open)状态。该超时时间的设定是给了系统一次机会来修正导致调用失败的错误
  • Open:打开状态(断路器打开),所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭认失败比例的阈值是50%,请求次数最少不低于20次。
  • Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(认是5S)。随后断路器会自动进入半开状态。此时会释放1次请求通过,若这个请求是健康的,则会关闭断路器,否则继续保持打开,再次进行5秒休眠计时。
为了能够精确控制请求的成功或失败,我们在 shop_service_product 调用业务中加入一段逻辑:
	@Autowired
	private RestTemplate restTemplate;

	/**
	 * 使用注解配置熔断保护
	 *     fallbackmethod : 配置熔断之后的降级方法
	 */
	@HystrixCommand(fallbackMethod = "orderFallBack")
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
		if(id != 1) {
			throw  new  RuntimeException("服务器异常");
		}
		return restTemplate.getForObject("http://service-product/product/1",Product.class);
	}
这样如果参数是 id 1 ,一定失败,其它情况都成功。
我们准备两个请求窗口:
一个请求: http://localhost:8080/consumer/1 ,注定失败
一个请求: http://localhost:8080/consumer/2 ,肯定成功
熔断器的认触发阈值是 20 次请求,不好触发。休眠时间时 5 秒,时间太短,不易观察,为了测试方便,我们可以通过配置修改熔断策略:
  • requestVolumeThreshold:触发熔断的最小请求次数20
  • errorThresholdPercentage:触发熔断的失败请求最小占比,50%
  • sleepWindowInMilliseconds:熔断多少秒后去尝试请求
hystrix:
  command:
    default:
      circuitBreaker:
        requestVolumeThreshold: 5 #触发熔断的最小请求次数认20 /10秒
        sleepWindowInMilliseconds: 10000 #熔断多少秒后去尝试请求 认 5   打开状态的时间
        errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,认50%
当我们疯狂访问 id 1 的请求时(超过 10 次),就会触发熔断。断路器会端口,一切请求都会被降级处理。
此时你访问 id 2 的请求,会发现返回的也是失败,而且失败时间很短,只有 20 毫秒左右。

6.3 熔断器的隔离策略

微服务使用 Hystrix 熔断器实现了服务的自动降级,让微服务具备自我保护的能力,提升了系统的稳定性,也较好的解决雪崩效应。其使用方式目前支持两种策略:
  • 线程池隔离策略:使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢处理)
  • 信号量隔离策略:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃改类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)。
线程池和型号量两种策略功能支持对比如下:

hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: ExecutionIsolationStrategy.SEMAPHORE #信号量隔离
          #strategy: # ExecutionIsolationStrategy.THREAD 线程池隔离

7 服务熔断Hystrix的替换方案

18 年底 Netflflix 官方宣布 Hystrix 已经足够稳定,不再积极开发 Hystrix ,该项目将处于维护模式。就目前来看Hystrix 是比较稳定的,并且 Hystrix 只是停止开发新的版本,并不是完全停止维护, Bug 什么的依然会维护的。因此短期内,Hystrix 依然是继续使用的。但从长远来看, Hystrix 总会达到它的生命周期,那么Spring Cloud 生态中是否有替代产品呢?

7.1 替换方案介绍

Alibaba Sentinel

Sentinel 是阿里巴巴开源的一款断路器实现,目前在Spring Cloud的孵化器项目Spring Cloud Alibaba中的一员Sentinel本身在阿里内部已经被大规模采用,非常稳定。因此可以作为一个较好的替代品。

Resilience4J

Resilicence4J 一款非常轻量、简单,并且文档非常清晰、丰富的熔断工具,这也是Hystrix官方推荐的替代产品。不仅如此,Resilicence4j还原生支持Spring Boot 1.x/2.x,而且监控也不像Hystrix一样弄Dashboard/Hystrix等一堆轮子,而是支持MicrometerPivotal开源的监控门面,Spring Boot 2.x中的Actuator就是基于Micrometer的)、prometheus(开源监控系统,来自谷歌的论文)、以及Dropwizard metrics(Spring Boot曾经的模仿对象,类似于Spring Boot)进行整合。

7.2 Sentinel概述

7.2.1 Sentinel简介

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

  • 丰富的应用场景Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 SpringCloud、dubbogRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。
  • 完善的SPI扩展点Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Sentinel 的主要特性:

7.2.2 SentinelHystrix的区别Sentinel

7.2.3 迁移方案

7.2.4 名词解释

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard 。核心库不依赖 Dashboard ,但是结合Dashboard 可以取得最好的效果
使用 Sentinel 来进行熔断保护,主要分为几个步骤 :
  • 1. 定义资源
  • 2. 定义规则
  • 3. 检验规则是否生效
资源 :可以是任何东西,一个服务,服务里的方法,甚至是一段代码
规则 Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则和热点参数规则。Sentinel 的所有规则都可以在内存态中动态地查询修改修改之后立即生效先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。

7.3 Sentinel中的管理控制台

7.3.1 下载启动控制台

1 获取 Sentinel 控制台
您可以从官方 网站中 下载最新版本的控制台 jar 包,下载地址如下: https://github.com/alibaba/Sentinel/releases/download/1.6.3/sentinel-dashboard-1.6.3.jar
2 )启动
使用如下命令启动控制台:
  • 其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080
  • Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能用户名和密码都是 sentinel 。可以参考鉴权模块文档配置用户名和密码。
  • 启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

7.3.2 客户端能接入控制台

控制台启动后,客户端需要按照以下步骤接入到控制台。
1 引入 JAR
客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。可以通过 pom.xml 引入 JAR :
2 )配置启动参数
在工程的 application.yml 添加 Sentinel 控制台配置信息

7.3.3 查看机器列表以及健康情况

认情况下 Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。也可以配置
sentinel.eager=true , 取消 Sentinel 控制台懒加载。
打开浏览器即可展示 Sentinel 的管理控制台

7.4 基于Sentinel的服务保护

7.4.1 通用资源保护
1 案例准备
复制工程 shop_service_order 并命名为 shop_service_order_rest_sentinel
2 )引入依赖
需要注意 SpringCloud-Alibaba SpringCloud 的版本关系。父工程引入alibaba实现的 SpringCloud。
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
子工程中引入 sentinel
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
3 在客户端配置启动参数
spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080   #sentinel控制台的请求地址
(4 配置熔断降级方法
在需要被保护的方法上使用 @SentinelResource 注解进行熔断配置。与 Hystrix 不同的是, Sentinel 对抛出异常和熔断降级做了更加细致的区分,通过 blockHandler 指定熔断降级方法,通过 fallback 指定触发异常执行的降级方法。对于@SentinelResource 的其他配置如下表:
特别地,若 blockHandler fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler fallback defaultFallback ,则被限流降级时会将 BlockException 直接抛出

7.4.2 Rest实现熔断

Spring Cloud Alibaba Sentinel 支持RestTemplate 的服务调用使用 Sentinel 进行保护,在构造RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。

  • @SentinelRestTemplate 注解的属性支持限流( blockHandler , blockHandlerClass )和降级( fallback , fallbackClass )的处理。
  • 其中 blockHandler fallback 属性对应的方法必须是对应 blockHandlerClass 或fallbackClass 属性中的静态方法
  • 方法的参数跟返回值跟 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中参数多出了一个 BlockException 参数用于获取 Sentinel 捕获的异常。
比如上述 @SentinelRestTemplate 注解中 ExceptionUtil handleException 属性对应的方法声明如下:
public class ExceptionUtils {

	/**
	 * 静态方法
	 *      返回值: SentinelClientHttpResponse
	 *      参数 : request , byte[] , clientRquestExcetion , blockException
	 */
	//限流熔断业务逻辑
	public static SentinelClientHttpResponse handleBlock(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
		return new SentinelClientHttpResponse("abc");
	}

	//异常降级业务逻辑
	public static SentinelClientHttpResponse handleFallback(HttpRequest request, byte[] body,
		ClientHttpRequestExecution execution, BlockException ex) {
		return new SentinelClientHttpResponse("def");
	}

}
Sentinel RestTemplate 限流的资源规则提供两种粒度:
  • httpmethod:schema://host:port/path :协议、主机、端口和路径
  • httpmethod:schema://host:port :协议、主机和端口

7.4.3 Feign实现熔断

Sentinel 适配了 Feign 组件。如果想使用,除了引入 sentinel - starter 的依赖外还需要 2 个步骤:
  • 配置文件打开 sentinel feign 支持feign.sentinel.enabled=true。
  • 加入 openfeign starter 依赖使 sentinel starter 中的自动化配置类生效。
1 引入依赖
        <!--feign对sentinel的支持-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
2 开启 sentinel 支持
在工程的 application.yml 添加 sentinel feign 支持
#激活sentinel的支持
feign:
  sentinel:
    enabled: true
3 )配置 FeignClient
和使用 Hystrix 的方式基本一致,需要配置 FeignClient 接口以及通过 fallback 指定熔断降级方法
/**
 * 声明需要调用的微服务名称
 *  @FeignClient
 *      * name : 服务提供者的名称
 *      * fallback : 配置熔断发生降级方法
 *                  实现类
 */
@FeignClient(name="service-product",fallback = ProductFeignClientCallBack.class)
public interface ProductFeignClient {

	/**
	 * 配置需要调用的微服务接口
	 */
	@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable("id") Long id);
}
4 )配置熔断方法
@Component
public class ProductFeignClientCallBack implements ProductFeignClient {

	/**
	 * 熔断降级的方法
	 */
	public Product findById(Long id) {
		Product product = new Product();
		product.setProductName("feign调用触发熔断降级方法");
		return product;
	}
}
@FeignClient 注解中的所有属性,Sentinel 都做了兼容。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐