springcloud学习3

一、断路器模式
断路器提供了后备(fallback)行为和自校正功能。
如果受保护的方法在给定的失败阈值内失败,那么可以调用一个后备方法代替它的位置。 在断路器处于打开状态后,几乎始终都会调用后备方法。处于打开状态的断路器偶尔进入半开状态,并尝试调用发生失败的方法。 如果仍然失败,断路器就恢复为打开状态; 如果调用成功,它会认为问题已经解决,断路器会回到闭合状态。
断路器是应用到方法上的。在一个微服务中,很容易有数十个断路器。以下几类方法是添加断路器的首选。

1.进行REST调用的方法:可能会因为远程服务不可用或返回HTTP500响应而失败。
2.执行数据库查询的方法:如果由于某种原因,数据库没有响应,或者模式变更破坏了应用而导致失败。
3.可能会比较慢的方法:它们不一定会失败,但如果他们的耗费了太长时间才能完成工作就可能会被视为失败。

二、声明断路器
引入依赖:
Spring Cloud Netflix Hystrix starter依赖到每个服务的构建文件中。在Maven pom.xml文件,Hystrix 依赖如下:

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

作为Spring Cloud套件的一部分,还需要在构建文件中声明Spring Cloud release train的依赖管理。如:
pom.xml:

  <properties>
		  <!-- .....省略其他 -->        
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
  </properties>
  <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>

启用Hystrix,在应用的主配置类上添加@EnableHystrix注解。如:

@EnableHystrix
@SpringBootApplication
public class HystrixDemoApplication {
    
    

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

}

这样就启用了Hystrix了。接下来,在代码中声明断路器,使用@HystrixCommand注解。
任何带有@HystrixCommand注解的方法都将被声明一个断路器切面。 例如,使用负载均衡RestTemplate从配料服务中获取一组Ingredient对象的列表:

public Iterable<Ingredient> getAllIngredients() {
    
    
 ParameterizedTypeReference<List<Ingredient>> stringList = new ParameterizedTypeReference<List<Ingredient>>() {
    
    };
 	return rest.exchange("http://ingredient-service/ingredients", HttpMethod.GET, HttpEntity.EMPTY, stringList).getBody();
}

exchange()的调用可能会遇到问题,如果Eureka没有注册名为ingredient-service的服务或者由于某种原因请求失败了,那么将会抛出RestClientException。在微服务中,当遇到失败的时候,微服务应该应用Vegas Rules规则:在微服务中发生的事情,就留在微服务中。在getAllIngredients()方法上声明断路器将会满足该规则。
在该方法加上 @HystrixCommand注解即可。

@HystrixCommand(fallbackMethod="getDefaultIngredients")
public Iterable<Ingredient> getAllIngredients() {
    
    
 //...
}

断路器为getAllIngredients()提供了失败保护,在遇到了未捕获的异常,那么断路器将会捕获它们并将方法调用重定向到名为getDefaultIngredients()方法上。

后备方法可以做任何事情,唯一规则是它们要与原始方法具有相同的签名(除了方法名称之外)。

为了满足这一要求,getAllIngredients()方法不接收任何参数并要返回List<Ingredient>。 如:

private Iterable<Ingredient> getDefaultIngredients() {
    
     
	 List<Ingredient> ingredients = new ArrayList<>(); 
	 ingredients.add(new Ingredient("FLTO", "Flour Tortilla", Ingredient.Type.WRAP)); 
	 ingredients.add(new Ingredient("GRBF", "Ground Beef", Ingredient.Type.PROTEIN)); 
	 ingredients.add(new Ingredient("CHED", "Shredded Cheddar", Ingredient.Type.CHEESE)); 
	 return ingredients; 
}

现在,如果getAllIngredients()方法失败,那么断路器将会调用备用的getDefaultIngredients()。
注:备用方法也可能会失败,可以也加上@HystrixCommand。可以堆积任意数量的备用方法。唯一要求就是必须在后备方法的底部有一个不会失败的方法,该方法不需要使用断路器
1、缓解延迟
断路器还能缓解延迟。如果某个方法需要较长时间才能返回,断路器会将它设置为超时。默认情况,用@HystrixCommand注解的方法都会在1秒后超时,并调用它们所声明的后备方法。 这意味着,如果由于某种原因,配料服务反应迟缓,那么在1秒后将调用getDefaultIngredients()作为替代方案。
默认值1秒,适用于大多数的场景。可以通过Hystrix命令属性调整为更大或更小的限制值。
@HystrixCommand的commandProperties属性:

    @HystrixCommand(
            fallbackMethod="getDefaultIngredients",
            commandProperties={
    
    
                    @HystrixProperty(
                            name="execution.isolation.thread.timeoutInMilliseconds",
                            value="500")
            })
   public Iterable<Ingredient> getAllIngredients() {
    
    
	   // ...
   }

如果想不使用超时功能,那么可以将execution.timeout.enabled属性设置成 false,直接将超时功能移除:

    @HystrixCommand(
            fallbackMethod="getDefaultIngredients",
            commandProperties={
    
    
                    @HystrixProperty(
                            name="execution.timeout.enabled",
                            value="false")
            })
   public Iterable<Ingredient> getAllIngredients() {
    
    
	   // ...
   }

execution.timeout.enabled属性设置成 false就没有延迟防护了。这可能导致级联的延迟效果,所以在禁用执行超时需小心。
2、管理断路器的阈值
默认情况下,如果一个断路器保护的方法被调用超过20次,并且超过50%的调用在10秒钟内失败,则该断路器将进入打开状态。所有的后续调用都将由后备方法来处理。5秒钟后,断路器将进入半开状态,将再次尝试原始方法。
可以通过设置HystrixCommand属性来调整失败和重试阈值。 以下命令属性将影响断路器的行为:

circuitBreaker.requestVolumeThreshold 在给定的时间段内,方法应该被调用的次数
circuitBreaker.errorThresholdPercentage 在给定的时间段内,方法调用产生失败的百分比
metrics.rollingStats.timeInMilliseconds 控制请求量和错误百分比的滚动时间周期
circuitBreaker.sleepWindowInMilliseconds 打开状态的断路器要经过多次时间进入半开状态,进入半开状态后,将会再次尝试失败的原始方法

如果在metrics.rollingStats.timeInMilliseconds设定的时间范围内超出了circuitBreaker.requestVolumeThreshold和circuitBreaker.errorThresholdPercentage设置的值,那么断路器将会进入打开状态。在 circuitBreaker.sleepWindowInMilliseconds限定时间范围内,它会一直处于打开状态,在此之后将进入半开状态,进入半开状态后,将会再次尝试失败的原始方法。
如,调整失败的设置:将其变更为在20秒的时间范围内调用超过30次且失败率超过25%。需要设置以下HystrixCommand属性:

 @HystrixCommand(
          fallbackMethod="getDefaultIngredients",
          commandProperties={
    
    
                  @HystrixProperty(
                          name="circuitBreaker.requestVolumeThreshold",
                          value="30"),
                  @HystrixProperty(
                          name="circuitBreaker.errorThresholdPercentage",
                          value="25"),
                  @HystrixProperty(
                          name="metrics.rollingStats.timeInMilliseconds",
                          value="20000")
          })
  public Iterable<Ingredient> getAllIngredients() {
    
    
	// ...
  }

另外,还想处于打开状态之后断路器必须保持1分钟,然后进入半开状态,那么需要设置circuitBreaker.sleepWindowInMilliseconds命令属性:


 @HystrixCommand(
        fallbackMethod="getDefaultIngredients",
        commandProperties={
    
    
       // ...
        @HystrixProperty(
                name="circuitBreaker.sleepWindowInMilliseconds",
                value="60000")
        })
  public Iterable<Ingredient> getAllIngredients() {
    
    
	// ...
  }

Hystrix还为应用中的每个断路器提供了一个指标流。
三、监控失败
每次调用断路器保护方法时,都会收集有关调用的数据,并在HTTP流中发布,这些数据可用于实时监测正在运行的应用程序的健康状况。 在为每个断路器收集的数据中,Hystrix流包括以下内容:

方法被调用了多少次
调用成功了多少次
后备方法调用了多少次
方法超时了多少次

Hystrix 流是由 Actuator 端点提供的。
添加依赖到pom.xml中,如:

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

Hystrix流端点会通过"/actuator/hystrix.stream"路径对外暴露。默认情况下,大多数的端点是被禁用的。可以通过在每个应用的application.yml文件添加以下配置来启用Hystrix端点:

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

还可以将 management:endpoints:web:exposure:include属性放到 Config Server对外提供配置属性的application.yml中,这样全局所有的服务就可以使用它了。
应用启用后,将会暴露Hystrix流(这个流可以被任意的REST端点消费)。
1.Hystrix Dashboard
要使用Hystrix Dashboard,先创建一个Spring Boot应用并添加对Hystrix dashboard starter的依赖。
pom.xml:

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

为主配置类添加@EnableHystrixDashboard注解来启用 Hystrix Dashboard:

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
    
    
	 public static void main(String[] args) {
    
    
	 	SpringApplication.run(HystrixDashboardApplication.class, args);
	 }
}

在开发阶段,可能会让Hystrix Dashboard与其他服务一起在本地机器运行,还包括Eureka和Config Server。为了避免端口冲突,需要为Hystrix Dashboard选取一个唯一的端口。在Dashboard应用的application.yml文件中,可以将server.port设置成任意唯一的值,比如:
application.yml:

server:
 port: 7979

运行应用,在浏览器输入http:localhost:7979/hystrix

四、聚合多个Hystrix流
Hystrix dashboard一次只能监控一个流,因为每个微服务实例都发布它们自己的Hystrix。
Netflix的另一个项目Turbine提供了将所有微服务的所有Hystrix流聚合到一个Hystrix流中的方法。
1、引入turbine依赖:

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

2、在创建完项目后,启用Turbine,需要在主配置类上添加@EnableTurbine注解

@SpringBootApplication
@EnableTurbine
public class TurbineServerApplication {
    
    
	 public static void main(String[] args) {
    
    
	 	SpringApplication.run(TurbineServerApplication.class, args);
	 }
}

为了避免端口冲突,Turbine选择一个唯一的端口,比:

server:
 port: 8989

Turbine会消费多个微服务的流并将它们的断路器指标合并到一个流中。它会作为Eureka客户端,发现那些需要聚合到自己的流的服务。但是,Turbine并不想聚合Eureka中注册的所有流,所有要配置Turbine,告诉它都要使用哪些服务。
设置turbine.app-config
application.yml:

turbine:
 app-config: ingredient-service,taco-service,order-service,user-service
 cluster-name-expression: "'default'"	

turbine.cluster-name-expression属性设置成了default,表示Turbine会收集名为default的集群中的所有聚合流。如果不设置这个属性,表示turbin不会包含任何特定应用的聚合流数据。

猜你喜欢

转载自blog.csdn.net/tongwudi5093/article/details/114319519