【Spring Cloud Hystrix】【一】:服务容错快速入门

一、Why服务容错

       在微服务架构中,需要将系统拆分成多个服务单元,各单元的应用间通过服务注册与订阅的方式相互依赖。由于服务之间通过远程过程调用RPC的方式执行,就有可能因为网络原因或者依赖服务自身问题造成调用失败或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因等待出现故障的依赖方响应延迟造成任务积压,最终导致自身服务的瘫痪。

        举个例子,我们的系统中分为A,B,C等服务单元。用户的调用链为:User -> A -> B -> C。在用户User请求A的时候,A回去请求B,B去请求C,当服务C因为自身处理逻辑以及网络原因导致响应缓慢,会直接导致服务B中请求C的线程被阻塞,接连导致A中线程阻塞,在漫长的等待过程中,User会得到调用失败的结果。如果在高并发情况之下,因为下游服务C故障而影响上游服务,将A,B服务"拖死",导致不可用。

       在微服务架构中,存在着那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较于传统架构更加不稳定。为了解决这些问题,就产升了服务容错保护机制等组件。而在SpringCloud中,这个强大的组件就是Hystrix,下面会通过搭建服务介绍hystrix的使用,包括超时设置,降级处理等。

二、快速入门

2.1 Consumer构建

首选要在consumer工程pom文件中引入hystrix组件:

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

工程主类ConsumerApplication中使用@EnableCircuitBreaker注解来开启断路器功能:

EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
@EnableHystrix
@SpringBootApplication(exclude = PageHelperAutoConfiguration.class)
public class ConsumerApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
        System.out.println("ヾ(◍°∇°◍)ノ゙    Spring Boot Application Boot SUCCESS   ヾ(◍°∇°◍)ノ゙\n" +
                " ______                    _   ______            \n" +
                "|_   _ \\                  / |_|_   _ `.          \n" +
                "  | |_) |   .--.    .--. `| |-' | | `. \\  .--.   \n" +
                "  |  __'. / .'`\\ \\/ .'`\\ \\| |   | |  | |/ .'`\\ \\ \n" +
                " _| |__) || \\__. || \\__. || |, _| |_.' /| \\__. | \n" +
                "|_______/  '.__.'  '.__.' \\__/|______.'  '.__.'  ");
    }

    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        // 注意这里要指向原先用main方法执行的Application启动类
        return builder.sources(ConsumerApplication.class);
    }

}

ConsumerController定义:

@RestController
@RequestMapping("/springcloud/consumer/hystrix")
public class HystrixController extends BaseController {

    @Resource
    private HelloService helloService;

    @GetMapping("/timeout")
    public String hystrixTimeout() {

        String resStr = helloService.hello();

        System.out.println(resStr);

        return success(resStr);
    }
}

HelloService接口定义:

public interface HelloService {
    String hello();
}

HelloServiceImpl实现:

@Service
public class HelloServiceImpl implements HelloService {

    @Resource
    private HelloFeign helloFeign;

    @Override
    @HystrixCommand(commandKey = "testKey", groupKey = "testGroup")
    public String hello() {
        return helloFeign.hello();
    }
}

FeignClient定义:

@FeignClient(name = "provider-service")
public interface HelloFeign {

    @GetMapping(value = "/springcloud/privoder/hello")
    String hello();
}

hystrix配置文件:

hystrix:
  threadpool:
    testGroup:
      coreSize: 20
      maximumSize: 100
      allowMaximumSizeToDivergeFromCoreSize: true
      maxQueueSize: 200
      queueSizeRejectionThreshold: 1000
  command:
    testKey:
      execution:
        timeout:
          enabled: true
        isolation:
          strategy: THREAD
          thread:
            timeoutInMilliseconds: 1000
            interruptOnTimeout: true
            interruptOnFutureCancel: false
          semaphore:
            maxConcurrentRequests: 5000

2.2 Provider构建

 

 

@Slf4j
@RestController
@RequestMapping("/springcloud/provider")
public class ProviderController extends BaseController {
    
    @GetMapping(value = "/hello")
    public String hello() throws Exception{

        //让处理线程随机等待sleepTime毫秒
        int sleepTime = new Random().nextInt(3000);
        Thread.sleep(sleepTime);
        System.out.println("elapse time = " + sleepTime);
        return success("hello hystrix elapse " + sleepTime);
    }
}

2.3 演练

生产者模拟超时处理时间为0~3000ms,消费者请求的超时时间为1000ms,参数为:timeoutInMilliseconds,通过多次请求消费者,可以观察到两种结果:

1.返回结果正常,返回码200,响应时间<1000ms

{"errno":0,"data":{},"errmsg":"{\"errno\":0,\"data\":{},\"errmsg\":\"hello hystrix elapse 774\"}"}

2.返回结果异常,返回码500,响应时间>1000ms

{
    "timestamp": "2020-01-05T07:10:39.470+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "testKey timed-out and fallback failed.",
    "trace": "com.netflix.hystrix.exception.HystrixRuntimeException:",
    "path": "//springcloud/consumer/hystrix/timeout"
}

三、超时设定及服务降级

       有时候我们需要捕获异常情况,并返回自定义的信息给上游,也是所谓的"服务降级"。fallback是Hystrix命令执行失败时使用后备方法,用来实现服务的降级处理逻辑。通过@HystrixCommand中的fallbackMethod参数来指定具体的服务降级实现方法。

@Service
public class HelloServiceImpl implements HelloService {

    @Resource
    private HelloFeign helloFeign;

    @Override
    @HystrixCommand(fallbackMethod = "helloFallback", commandKey = "testKey", groupKey = "testGroup")
    public String hello() {
        return helloFeign.hello();
    }

    public String helloFallback() {
        return "hello fallback";
    }
}

在使用注解来定义服务降级逻辑时,我们需要将具体的Hystrix命令与fallback实现函数定义在同一个类中,并且fallbackMethod的值必须与实现fallback方法的名字相同。由于必须定义在一个类中,所以对于fallback的访问修饰符没有特定的要求,定义为private,public,protected都行。

异常返回结果为(>1000ms):

{"errno":0,"data":{},"errmsg":"hello fallback"}

Author:忆之独秀

Email:[email protected]

转载注明出处:https://blog.csdn.net/lavorange/article/details/103843058

             

发布了130 篇原创文章 · 获赞 114 · 访问量 48万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章