• Spring Cloud使用Zuul实现容错回退功能

    Zuul 主要功能就是转发,在转发过程中我们无法保证被转发的服务是可用的,这个时候就需要容错机制及回退机制。

    容错机制

    容错,简单来说就是当某个服务不可用时,能够切换到其他可用的服务上去,也就是需要有重试机制。在 Zuul 中开启重试机制需要依赖 spring-retry。

    首先在 pom.xml 中添加 spring-retry 的依赖,代码如下所示。

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>

    在属性文件中开启重试机制以及配置重试次数:

    zuul.retryable=true
    ribbon.connectTimeout=500
    ribbon.readTimeout=5000
    ribbon.maxAutoRetries=1
    ribbon.maxAutoRetriesNextServer=3
    ribbon.okToRetryOnAllOperations=true
    ribbon.retryableStatusCodes=500,404,502

    其中:

    • zuul.retryable:开启重试。
    • ribbon.connectTimeout:请求连接的超时时间(ms)。
    • ribbon.readTimeout:请求处理的超时时间(ms)。
    • ribbon.maxAutoRetries:对当前实例的重试次数。
    • ribbon.maxAutoRetriesNextServer:切换实例的最大重试次数。
    • ribbon.okToRetryOnAllOperations:对所有操作请求都进行重试。
    • ribbon.retryableStatusCodes:对指定的 Http 响应码进行重试。

    可以启动两个 hystrix-feign-demo 服务,默认 Ribbon 的转发规则是轮询,然后我们停掉一个 hystrix-feign-demo 服务。没加重试机制之前,当你请求接口的时候肯定有一次是会被转发到停掉的服务上去的,返回的是异常信息。

    当我们加入了重试机制后,你可以循环请求接口,这个时候不会返回异常信息,因为 Ribbon 会根据重试配置进行重试,当请求失败后会将请求重新转发到可用的服务上去。

    回退机制

    在 Spring Cloud 中,Zuul 默认整合了 Hystrix,当后端服务异常时可以为 Zuul 添加回退功能,返回默认的数据给客户端。

    实现回退机制需要实现 ZuulFallbackProvider 接口,代码如下所示。

    @Component
    public class ServiceConsumerFallbackProvider implements ZuulFallbackProvider {
        private Logger log = LoggerFactory.getLogger(ServiceConsumerFallbackProvider.class);
    
        @Override
        public String getRoute() {
            return "*";
        }
    
        @Override
        public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
            return new ClientHttpResponse() {
                @Override
                public HttpStatus getStatusCode() throws IOException {
                    return HttpStatus.OK;
                }
    
                @Override
                public int getRawStatusCode() throws IOException {
                    return this.getStatusCode().value();
                }
    
                @Override
                public String getStatusText() throws IOException {
                    return this.getStatusCode().getReasonPhrase();
                }
    
                @Override
                public void close() {
                }
    
                @Override
                public InputStream getBody() throws IOException {
                    if (cause != null) {
                        log.error("", cause.getCause());
                    }
                    RequestContext ctx = RequestContext.getCurrentContext();
                    ResponseData data = ResponseData.fail("服务器内部错误 ", ResponseCode.SERVER_ERROR_CODE.getCode());
                    return new ByteArrayInputStream(JsonUtils.toJson(data).getBytes());
                }
    
                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders headers = new HttpHeaders();
                    MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
                    headers.setContentType(mt);
                    return headers;
                }
            };
        }
    }

    getRoute 方法中返回*表示对所有服务进行回退操作,如果只想对某个服务进行回退,那么就返回需要回退的服务名称,这个名称一定要是注册到 Eureka 中的名称。

    通过 ClientHttpResponse 构造回退的内容。通过 getStatusCode 返回响应的状态码。通过 getStatusText 返回响应状态码对应的文本。通过 getBody 返回回退的内容。通过 getHeaders 返回响应的请求头信息。

    通过 API 网关来访问 hystrix-feign-demo 服务,将 hystrix-feign-demo 服务停掉,然后再次访问,就可以看到回退的内容了,如图 1 所示。

    运行结果
    图 1  运行结果

更多...

加载中...