SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)

目录

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 依赖。
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
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的配置

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第1张图片

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 的源码。
SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第2张图片
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 支持最大的并发请求是有限的,如果某一接口阻塞,待执行的任务积压越来越多,那么势必会影响其他接口的调用。
SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第3张图片

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

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

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 {

	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 雪崩效应

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第4张图片

在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服务将处于阻塞状态,直到B服务C服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩效应。

雪崩是系统中的蝴蝶效应导致其发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。源头上我们无法完全杜绝雪崩源头的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估,做好熔断,隔离,限流。

5.1.2 服务隔离

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

5.1.3 熔断降级

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第5张图片

熔断这一概念来源于电子工程中的断路器(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 的相关依赖
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
        
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 的相关依赖。
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
        
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:9003/actuator/hystrix.stream , 即可看到实时的监控数据。
1 )导入依赖
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
        
2 )在启动类使用@EnableHystrixDashboard 注解激活仪表盘项目
//激活hystrix
@EnableCircuitBreaker
3 )暴露所有actuator监控的端点
#暴露所有端点
management:
  endpoints:
    web:
      exposure:
        include: '*'

6.1.1 搭建Hystrix DashBoard监控

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

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第6张图片

输入监控断点展示监控的详细数据:

http://localhost:9003/actuator/hystrix.stream

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第7张图片

6.1.2断路器聚合监控Turbine

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第8张图片

在微服务架构体系中,每个服务都需要配置Hystrix DashBoard监控。如果每次只能查看单个实例的监控数据,就需要不断切换监控地址,这显然很不方便。要想看这个系统的Hystrix Dashboard数据就需要用到Hystrix TurbineTurbine是一个聚合Hystrix 监控数据的工具,他可以将所有相关微服务的 Hystrix 监控数据聚合到一起,方便使用。引入Turbine后,整个监控系统架构如下:

1 )搭建TurbineServer
创建工程 shop_hystrix_turbine 引入相关坐标
        
            org.springframework.cloud
            spring-cloud-starter-netflix-turbine
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-hystrix-dashboard
        
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 熔断器的状态

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第9张图片

熔断器有三个状态 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。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)。
线程池和型号量两种策略功能支持对比如下:
SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第10张图片
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 的主要特性:
SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第11张图片

7.2.2 SentinelHystrix的区别Sentinel

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第12张图片

7.2.3 迁移方案

SpringCloud-2-基础组件(Feign、Hystrix、Sentinel)_第13张图片

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 )启动
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 - Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
使用如下命令启动控制台:
  • 其中 -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。
            
                com.alibaba.cloud
                spring-cloud-alibaba-dependencies
                2.1.0.RELEASE
                pom
                import
            
子工程中引入 sentinel
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        
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 引入依赖
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
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 都做了兼容。

你可能感兴趣的:(java,spring,spring,boot,sentinel,java-consul)