五、Hystrix断路器

1. 概念

  “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间等待或抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。

服务雪崩
多个微服务之间调用时,若微服务A调用B、C,而B、C又调用其他微服务,这就是所谓的“扇出”。若扇出的链路上某个微服务的调用响应时间过长或不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,即所谓的“雪崩效应”。

  Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖不可避免的会调用失败,比如超时、异常等。Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性

  Hystrix提供服务熔断服务降级等方式实现故障处理。

2. 服务熔断

2.1 概念

  服务熔断机制,是应对雪崩效应的一种微服务链路保护机制。
  当扇出链路的某个微服务不可用或长时间未响应时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的相应信息。当检测到该节点微服务调用响应正常后恢复调用链路。
  在SpringCloud框架中,Hystrix会监控微服务间的调用状况,当失败的调用达到一定阈值(缺省:15秒内20次调用失败),就会启动熔断机制,通过@HystrixCommand注解实现。

2.2 代码实现(Service Provider)

2.2.1 新建项目

在工程spring-cloud-demo下,新建module,名为service-member-hystrix-8010(参考service-member-8010)。

2.2.2 引入依赖

引入spring-cloud-starter-hystrix依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- 监控信息完善 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
    </dependency>
    <!-- hystrix -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
</dependencies>

2.2.3 添加yml文件

eureka:
  client: #将客户端注册进Eureka服务列表内
    serviceUrl:
      defaultZone: http://eureka7777.com:7777/eureka/,http://eureka8888.com:8888/eureka/,http://eureka9999.com:9999/eureka/
  instance:
    instance-id: service-member-hystrix-8010 #自定义Eureka微服务管理页面的显示别名
    prefer-ip-address: true #访问路径可以显示IP地址,默认为false 不显示
server:
  port: 8010
spring:
  application:
    name: service-member

info:
  app.name: charver-springclouddemo-servicemember
  company.name: www.chavaer.com
  contact.name: chavaer
  contact.phone: 188-3288-3388
  contace.email: chavaer@super.com.cn

2.2.4 添加Controller

  • 新建MemberController,将service-member-8010项目中的MemberController复制过来。
  • 对获取会员列表方法进行改造,若出现查询数据库异常,则进行异常处理。通过@HystrixCommand注解指定异常情况下需执行的方法processGetMember()。
  • 一旦调用方法失败并抛出异常信息后,会自动调用@HystrixCommand标注好的fallbackMethod方法。类似于Spring的异常通知。
  • 添加processGetMember()方法,返回提示内容。
@Controller
@RequestMapping("/member")
public class MemberController {

    @Autowired
    private DiscoveryClient client;

    @RequestMapping("/list")
    @ResponseBody
    @HystrixCommand(fallbackMethod = "processGetMember")
    public Map<String, String> getAllMember() {

		//构造异常
        throw new RuntimeException("查询数据库异常");
    }

    public Map<String, String> processGetMember() {

        HashMap<String, String> map = new HashMap<>(1);
        map.put("9999", "系统异常,请稍后访问!");
        return map;
    }

    @RequestMapping("/discovery")
    @ResponseBody
    public Object discovery() {

        System.out.println("Current client : " + client.description());

        List<String> services = client.getServices();
        System.out.println("Current service list : " + services);

        for (String service : services) {
            List<ServiceInstance> instances = client.getInstances(service);
            for (ServiceInstance instance : instances) {
                System.out.println(instance.getServiceId() + "\t" + instance.getHost() + "\t"
                        + instance.getPort() + "\t" + instance.getUri());
            }
        }

        return client;
    }
}

2.2.5 修改启动类

通过@EnableCircuitBreaker开启对hystrix熔断机制的支持。

@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册到Eureka服务列表中
@EnableDiscoveryClient //服务发现
@EnableCircuitBreaker //对hystrix熔断机制的支持
public class MemberHystrix8010App {

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

2.2.6 效果测试

分别启动各个微服务:
Eureka Server:eureka-server-7777、eureka-server-8888、eureka-server-9999
Service Provider:service-member-hystrix-8010
Service Consumer:service-order
在浏览器访问:http://localhost:8002/order/getMemberList ,获取会员列表,即可立即展示错误信息:
在这里插入图片描述

3. 服务降级

3.1 概念

  服务降级,简单来说,就是在系统资源紧张时,将某些资源暂时关闭,待系统正常,再重新开启。
  服务熔断,是在方法上加上@HystrixCommand注解,然后添加一个fallback方法,这会带来两个问题:① 每个方法都需要有一个对应的fallback方法,最终会造成方法膨胀;② 处理具体业务的方法,要配合fallback方法一起使用,耦合度太高
  基于此,借鉴Spring AOP思想,要实现业务逻辑方法与错误响应方法解耦分离,可以使用一个类,专门用于处理异常响应,与具体的业务逻辑分离开。服务降级的处理方式,就是这种思想。

  • 服务降级:是在客户端(服务消费者)完成,与服务端没有关系,配合@FeignClient注解使用,一般是对服务提供者关闭的情况做出备选响应。
  • 服务熔断:是在服务端(服务提供者)完成,配合@HystrixCommand注解使用,一般是一个业务逻辑方法对应一个响应处理方法。

3.2 代码实现(Service Consumer)

3.2.1 新建异常处理类

  在客户端(服务消费者)service-order-feign工程中,针对OrderClientService,新增一个异常处理的类OrderClientServiceFallbackFactory,实现FallbackFactory接口,泛型给定OrderClientService类型,重写方法create,返回匿名内部类(OrderClientService接口的实现类,重写接口的方法,内容为服务降级提示外界的信息)。
  OrderClientService接口中的方法都是调用服务端,服务端关闭,因此可以针对OrderClientService接口,覆写该接口中的所有方法,以达到服务降级提示外界的目的。

@Component
public class OrderClientServiceFallbackFactory implements FallbackFactory<OrderClientService> {

    @Override
    public OrderClientService create(Throwable throwable) {
        return new OrderClientService() {
            @Override
            public Map<String, String> getMemberList() {
                return (Map<String, String>)getShowInfo();
            }

            @Override
            public Object discovery() {
                return getShowInfo();
            }

            private Object getShowInfo() {
                HashMap<String, String> map = new HashMap<String, String>(1);
                map.put("9999", "暂停服务!");
                return map;
            }
        };
    }
}

  在OrderClientService接口中,有一个@FeignClient注解,可以指定值fallbackFactory为刚才新增的类OrderClientServiceFallbackFactory.class

//@FeignClient(value = "service-member")
@FeignClient(value = "service-member", fallbackFactory = OrderClientServiceFallbackFactory.class)
public interface OrderClientService {

    @RequestMapping("/member/list")
    Map<String, String> getMemberList();

    @RequestMapping("/member/discovery")
    Object discovery();
}

3.2.2 修改yml文件

  由于我们在service-order-feign的OrderClientService中,异常响应的处理类借助于@FeignClient,因此需要开启Feign对Hystrix的支持。

eureka:
  client:
    serviceUrl:
      defaultZone: http://eureka7777.com:7777/eureka/,http://eureka8888.com:8888/eureka/,http://eureka9999.com:9999/eureka/
    registerWithEureka: false #Service-order服务作为Eureka Client,不向注册中心注册

server:
  port: 8002

feign:
  hystrix:
    enabled: true

3.2.3 效果测试

分别启动各个微服务:
Eureka Server:eureka-server-7777、eureka-server-8888、eureka-server-9999
Service Provider:service-member-hystrix-8010
Service Consumer:service-order-feign

  • 正常情况下:
    测试服务发现接口:http://localhost:8002/order/memberDiscovery
    在这里插入图片描述
  • 手动停止service-member-hystrix-8010服务:
    测试服务发现接口:http://localhost:8002/order/memberDiscovery
    在这里插入图片描述

3.2.4 注意事项

  • 异常响应处理类OrderClientServiceFallbackFactory必须@Component被Spring容器管理;
  • @FeignClient注解的属性为fallbackFactory,若不慎写成fallback,会抛出创建bean失败的异常
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderController': Unsatisfied dependency expressed through field 'orderClientService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.charver.cloud.service.OrderClientService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Incompatible fallback instance. Fallback/fallbackFactory of type class com.charver.cloud.service.OrderClientServiceFallbackFactory is not assignable to interface com.charver.cloud.service.OrderClientService for feign client service-member

解决方式有两种:
① 第一种是将fallback修改为fallbackFactory。
② 第二种是将异常响应处理类OrderClientServiceFallbackFactory直接实现OrderService接口,而非实现FallbackFactory接口。

4. 服务监控

4.1 概念

  除隔离依赖服务的调用外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续的记录所有通过Hystrix发起的请求执行信息,并统计报表和图表的形式展示给用户,包括每秒执行多少次,成功与失败次数等。
  Netflix通过hystrix-metrics-event-stream项目实现对以上指标的监控,SpringCloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面

4.2 代码实现

4.2.1 新建项目

在工程spring-cloud-demo下新建一个module,名为service-hystrix-dashboard。

4.2.2 引入依赖

<!-- hystrix与hystrix-dashboard相关-->
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
    </dependency>
</dependencies>

4.2.3 修改yml文件

server:
  port: 9001

4.2.4 修改启动类

@EnableHystrixDashboard注解开启对Hystrix-Dashboard的支持。

@SpringBootApplication
@EnableHystrixDashboard
public class DashboardApp {

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

4.2.5 服务提供方添加监控依赖配置

服务提供者引入监控依赖,service-member-8010、service-member-8011、service-member-8012、service-member-hystrix-8010之前已引入依赖;

<!-- 监控信息完善 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
</dependency>

4.3 效果测试

分别启动各个微服务:
Eureka Server:eureka-server-7777、eureka-server-8888、eureka-server-9999
Service Provider:service-member-hystrix-8010
Hystrix Dashboard:service-hystrix-dashboard

  • 访问url:http://localhost:9001/hystrix,出现豪猪标志,说明Hystrix Dashboard服务监控配置启动成功。
    在这里插入图片描述

Delay:该参数用来控制服务器上轮询监控信息的延迟时间,默认为2000ms,可以通过配置该属性来降低客户端的网络与CPU消耗。
Title:该参数对应头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。

  • 现要实现service-hystrix-dashboard服务监控service-member-hystrix-8010服务的信息,访问url:http://localhost:8010/hystrix.stream
    在这里插入图片描述
    可发现,url在被不断自动刷新,且页面出现ping、data数据,这说明service-member-hystrix-8010服务已经在持续被监控了。
  • 为了直观的看到效果,可以在豪猪页面的url区域填写监控的目标url:http://localhost:8010/hystrix.stream,输入完成后,点击”Monitor Stream“按钮,可出现如下页面:
    在这里插入图片描述
    可看出目前正在监控着service-member-hystrix-8010服务的MemberController中的getAllMember方法,有Success | Short-Circuited | Timeout | Rejected | Failure | Error七种颜色表示其中状态。
    方法左边区域的实心圆,共有两种含义:① 通过颜色变化代表实例的健康程度,健康度从绿色→黄色→橙色→红色依次降低;② 通过大小变化代表实例的请求流量变化,流量越大,实心圆越大。通过实心圆的外观变化,快速的从大量实例中发现故障与高压力实例。
  • 在浏览器测试调用MemberController中的getAllMember方法,效果如下:
    -在这里插入图片描述
    在这里插入图片描述

【上一篇】四、Feign负载均衡
【下一篇】六、Zuul路由网关


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值