Spring Cloud学习(4)——服务容错保护Hystrix初研

阅读的书籍为《Spring Cloud 微服务实战》。

在微服务架构中,服务被拆分成了若干服务单元。各个服务单元应用间通过服务注册与订阅的方式相互依赖。

由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,可能会因为网络问题或者依赖服务自身的问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断的增加,最终就会因等待出现故障的依赖方响应形成任务积压,导致自身服务的瘫痪。

在微服务架构中,若一个单元出现故障,很容易因为依赖关系引发故障的蔓延,最终导致整个系统的瘫痪,故需要断路器等一系列的服务保护机制。

使用断路器模式,可以通过断路器的故障监控,向调用方返回一个错误响应,而不是长时间的等待,不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。

未加入断路器前的测试

采用《Spring Cloud学习(3)——服务发现与消费以及客户端负载均衡Ribbon》中的几个服务:

两个Eureka Server实例,两个HELLO-WORLD-SERVICE实例,一个RIBBON-DEMO实例。

这里写图片描述

未加入断路器,关闭一个HELLO-WORLD-SERVICE实例。访问http://localhost:9000/ribbon-test。会出现以下错误:

这里写图片描述

加入Hystrix后的测试

改造RIBBON-DEMO服务

  • 在ribbon-demo工程pom.xml中,加入spring-cloud-starter-hystrix的依赖。

  • 在主类里使用@EnableCircuitBreaker注解,开启断路器功能。

也可以使用@SpringCloudApplication注解,来代替下面三个注解。

@EnableDiscoveryClient
@SpringBootApplication
@EnableCircuitBreaker
  • 修改ConsumerController,增加@HystrixCommand注解来指定回调方法。
    在消费者调用函数中做时间记录,测试下文模拟的服务阻塞场景
package com.example.ribbondemo.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class ConsumerController {
    @Autowired
    RestTemplate restTemplate;

    private final Logger log = Logger.getLogger(getClass());

    @RequestMapping(value = "/ribbon-test", method = RequestMethod.GET)
    @HystrixCommand(fallbackMethod = "ribbonTestFallback")
    public String ribbonTest() {
        long start = System.currentTimeMillis();
        String result = restTemplate.getForEntity("http://HELLO-WORLD-SERVICE/helloworld", String.class).getBody();
        long end = System.currentTimeMillis();
        log.info("Spend time : " + (end - start));
        return result;
    }

    public String ribbonTestFallback() {
        return "error";
    }
}

改造HELLO-WORLD-SERVICE服务

修改HELLO-WORLD-SERVICE中的/helloworld接口,模拟服务阻塞的情况。
Hystrix默认的超时时间为2000毫秒,这里采用0-3000的随机数,阻塞线程,使有一定概率触发断路器。

package com.example.helloworld.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.apache.log4j.Logger;

import java.util.List;
import java.util.Random;

@RestController
public class HelloworldController {
    private final Logger log = Logger.getLogger(getClass());

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping(value = "/helloworld", method = RequestMethod.GET)
    public String helloworld() throws Exception {
        int sleepTime = new Random().nextInt(3000);
        log.info("sleepTime : " + sleepTime);
        Thread.sleep(sleepTime);
        log.info("discoveryClient.getServices().size() = " + discoveryClient.getServices().size());
        for (String s : discoveryClient.getServices()) {
            log.info("services " + s);
            List<ServiceInstance> serviceInstances = discoveryClient.getInstances(s);
            for (ServiceInstance si : serviceInstances) {
                log.info("    services:" + s + ":getHost()=" + si.getHost());
                log.info("    services:" + s + ":getPort()=" + si.getPort());
                log.info("    services:" + s + ":getServiceId()=" + si.getServiceId());
                log.info("    services:" + s + ":getUri()=" + si.getUri());
                log.info("    services:" + s + ":getMetadata()=" + si.getMetadata());
            }
        }
        return "hello world";
    }
}

测试

这里写图片描述
当访问出现error的时候,观察HELLO-WORLD-SERVICE实例的控制台,发现:
这里写图片描述
当控制台输出的Spend time大于2000时,就会返回error。即服务消费者因调用的服务超时,从而触发熔断请求,并调用回调逻辑,返回结果。

猜你喜欢

转载自blog.csdn.net/huqigang/article/details/79410158