# 快速搭建微服务-熔断器

熔断器的主要功能是在进行服务间调用时提供一种容错保护,当服务提供方因网络或自身原因出现调用故障或延迟时,会导致服务调用方对外服务也出现延迟,如果此时服务调用方的请求不断增加,则会出现调用方的自身服务的故障甚至蔓延导致整个系统的瘫痪。

# 服务调用方配置熔断

  • Maven依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
1
2
3
4
  • 开启熔断器

在启动类上加入@EnableCircuitBreaker注解开启熔断器。

  • 服务降级

通过 @HystrixCommand 注解实现服务降级。

@GetMapping("")
@HystrixCommand(fallbackMethod = "listWxMpAccountFallback")
public Result listWxMpAccount(@PageableDefault Pageable pageable) {
    return wxMpAccountService.listWxMpAccount(pageable);
}

private Result listWxMpAccountFallback(Pageable pageable) {
    return Result.fail("获取公众号列表失败,请稍后再试");
}
1
2
3
4
5
6
7
8
9

# 网关配置服务降级

当我们在使用zuul进行路由分发,如果后端服务没有启动或者调用超时的时候,就可以使用zuul提供的降级功能。

在网关服务中新建继承自 FallbackProviderServiceFallbackProvider 类,并使用 @Component 注解进行修饰。FallbackProvider 会根据是否存在 Throwable 来选择降级方法。

@Component
public class ServiceFallbackProvider implements FallbackProvider {

    @Override
    public ClientHttpResponse fallbackResponse(Throwable throwable) {
        StringBuilder reasonBuilder = new StringBuilder("服务故障,请稍后重试!");
        if (throwable != null && throwable.getCause() != null) {
            reasonBuilder.append(" 故障原因: ").append(throwable.getCause().getMessage());
        }
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.SERVICE_UNAVAILABLE;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.SERVICE_UNAVAILABLE.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase();
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream(reasonBuilder.toString().getBytes(Charset.forName("UTF-8")));
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.valueOf(AppConsts.WebConsts.TEXT_PLAIN_UTF8_VALUE));
                return headers;
            }
        };
    }

    @Override
    public String getRoute() {
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.SERVICE_UNAVAILABLE;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.SERVICE_UNAVAILABLE.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase();
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("服务故障,请稍后重试!".getBytes(Charset.forName("UTF-8")));
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.valueOf(AppConsts.WebConsts.TEXT_PLAIN_UTF8_VALUE));
                return headers;
            }
        };
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86