六:Spring Cloud 之服务降级与限流熔断-Ribbon+Hystrix

版权声明:本文为博主原创文章,觉得稍有帮助,可点赞、转载注明出处。 https://blog.csdn.net/chenghuaying/article/details/82720823

1. 简介

Netflix has created a library called Hystrix that implements the circuit breaker pattern. In a microservice architecture it is common to have multiple layers of service calls.
A service failure in the lower level of services can cause cascading failure all the way up to the user. When calls to a particular service reach a certain threshold (20 failures in 5 seconds is the default in Hystrix), the circuit opens and the call is not made. In cases of error and an open circuit a fallback can be provided by the developer.
Having an open circuit stops cascading failures and allows overwhelmed or failing services time to heal. The fallback can be another Hystrix protected call, static data or a sane empty value. Fallbacks may be chained so the first fallback makes some other business call which in turn falls back to static data.

  • Hystrix是netflix创建的一个用于服务降级、限流熔断的组件
  • 微服务架构中一个服务调用链任何一个环节都有可能出现异常
  • 若对异常没有合理的处理方式,则可能导致与此相关的功能不可用,甚至有可能引发雪崩现象
  • Hystrix可以很好的解决服务不可用问题,可采用直接返回错误状态码、静态提示数据、以及转调统一处理方法等方式对调用方及时做出相应

2. 代码实现

2.1涉及的模块

  • eureka-server-singleton:服务注册中心,端口8761
  • eureka-service: 服务提供者,通过profile指定不同端口模拟一组微服务,端口8762、8763
  • eureka-service-ribbon-hystrix:通过Ribbon调用服务提供者提供的服务,并提供限流熔断功能

2.2 源代码

2.2.1 Github地址

https://github.com/andyChenHuaYing/spring-cloud-demo

2.2.2 切换

通过tag切换git tag -d v1.0,若想修改,可根据此tag创建新的分支。

Spring Cloud 之服务发现与调用-Ribbon#2.3 eureka-server-singleton 没有任何区别

2.3 eureka-service

Spring Cloud 之服务发现与调用-Ribbon#2.4 eureka-service 没有任何区别

2.4 eureka-service-ribbon-hystrix

2.4.1整体实现步骤

  1. pom.xml中引入spring-cloud-starter-netflix-eureka-serverspring-cloud-starter-netflix-ribbonspring-cloud-starter-netflix-hystrix依赖
  2. application.yml中指定配置项:端口、application name、eureka-server地址
  3. SpringBoot 启动类添加注解@EnableHystrix开启使用Hystrix功能
  4. 使用@Bean @LoadBalanced向Spring容器注入org.springframework.web.client.RestTemplate 实例
  5. 在使用之处使用@Autowired public RestTemplate restTemplate; 获取实例,调用服务提供方提供的方法
  6. 在需要使用Hystrix服务降级、容错功能的方法上使用@HystrixCommand(fallbackMethod = "hiError")指定回调方法

2.4.2 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">
    <parent>
        <artifactId>spring-cloud-finchley-demo</artifactId>
        <groupId>org.oscar.scd</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-service-ribbon-hystrix</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

</project>

2.4.2 application.yml

server:
  port: 8766

spring:
  application:
    name: eureka-service-ribbon-hystrix

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

2.4.3 EurekaServiceRibbonHystrixApplication

package org.oscar.scd.eureka.service.ribbon.hystrix;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableHystrix
@EnableEurekaClient
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaServiceRibbonHystrixApplication {

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

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

2.4.4 HelloRibbonHystrixController、HelloRibbonHystrixService

  • HelloRibbonHystrixService:
package org.oscar.scd.eureka.service.ribbon.hystrix.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class HelloRibbonHystrixService {

    @Autowired
    public RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "hiError")
    public String hiService(String name) {
        return restTemplate.getForObject("http://eureka-service//print?name=" + name, String.class);
    }

    public String hiError(String name) {
        return "Hi " + name + ", sorry, system error.";
    }

}
  • HelloRibbonHystrixController:
package org.oscar.scd.eureka.service.ribbon.hystrix.controller;

import org.oscar.scd.eureka.service.ribbon.hystrix.service.HelloRibbonHystrixService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/ribbon/hystrix")
public class HelloRibbonHystrixController {

    @Autowired
    public HelloRibbonHystrixService service;

    @GetMapping("/print")
    public String print(@RequestParam String name) {
        return this.service.hiService(name);
    }
}

3. 验证

3.1 创建SpringBoot启动类

3.1.1 EurekaServerSingletonApplication

最简单的方式添加一个SpringBoot启动类型的启动类就行。

这里写图片描述

3.1.2 EurekaServiceApplication-8762

EurekaServiceApplication-8762

3.1.3 EurekaServiceApplication-8763

与8762相同,只是修改 Active profiles 为8763

3.1.4 EurekaServiceRibbonHystrixApplication

最简单的方式添加一个SpringBoot启动类型的启动类就行。

3.2 启动

  1. EurekaServerSingletonApplication
  2. EurekaServiceApplication-8762
  3. EurekaServiceApplication-8763
  4. EurekaServiceRibbonHystrixApplication

启动完成后Run Dashboard界面:
这里写图片描述

3.3 访问服务信息界面

此时服务都是正常注册状态!

这里写图片描述

3.4 服务提供者正常

  • 第一次访问,正常返回,服务提供者端口为:8763
    这里写图片描述

  • 第二次访问,也正常返回,服务提供者端口为:8762
    这里写图片描述

3.5 服务提供者异常

验证Hystrix是否生效,整体步骤

1. 停止端口为8762的服务提供者,观察eureka-server信息界面,服务是否下线以及再次调用服务,观察返回结果是否只有8763端口响应
2. 停止端口为8763的服务提供者,观察eureka-server信息界面,服务是否下线以及再次调用服务,观察返回结果是否是Hystrix服务熔断回调函数返回的结果
3. 若都是,则验证Hystrix功能生效

3.5.1 停止端口8762服务

  1. eureka-server信息界面:停止的8762没有像我们预期的下线,并且出现了红色的提示(eureka-server进入了自我保护模式-见补充部分)
    这里写图片描述

  2. 访问服务:绝大部分时间返回的是8763,8762服务刚停时,偶尔会返回Hystrix熔断回调函数的结果
    这里写图片描述

3.5.2 停止端口8763服务

  1. eureka-server信息界面:
    这里写图片描述
  2. 访问服务:只会返回Hystrix熔断回调函数的结果
    这里写图片描述

到这里,基本验证了Hystrix启作用了,但是这只是入门级别的使用,还有几个疑点后续解决。

4. 思考

  • 服务下线之后,eureka-server信息界面为什么只出现红色提示信息,并且没有将服务下线?或者说是服务已下线但是没有将服务状态标识为已下线或者不可用?
  • 这样设计的理由是什么?如何让已停止提供服务的服务信息在eureka-server中看的到呢
  • 为什么刚停止两个服务提供者之一时,访问服务信息会偶尔出现Hystrix熔断之后的回调函数处理结果?
  • Hystrix的处理方法能否指定使用单独的Thread或者ThreadPool来执行,

5. 补充

5.1 资料

5.2 Eureka 自我保护

Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),Eureka Server会将当前的实例注册信息保护起来,同时提示这个警告。保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。
解决方式(或者说处理措施,在后续详细使用或者问题整理中会解)

猜你喜欢

转载自blog.csdn.net/chenghuaying/article/details/82720823