Spring Cloud之Zuul(六):Zuul的容错与回退

主题

Zuul的容错与回退

前言

在Spring Cloud中,Zuul默认已经整合了Hystrix。首先我们结合前面的项目做一个简单的实验。

内容

1.启动项目

(1)启动cloud-discovery-enreka,port=8001

(2)启动cloud-register-user,port=8002

(3)启动cloud-register-gateway-zuul,port=8023

(4)启动cloud-hystrix-dashboard,port=8019

2.测试

(1)访问http://localhost:8023/cloud-register-user/1,即可获取正常结果

(2)访问http://localhost:8023/hystrix.stream,即可获取Hystrix的监控数据

(3)访问http://localhost:8019/hystrix,并在监控地址栏填入http://localhost:8023/hystrix.stream,即可获取如下结果

Spring Cloud之Zuul(六):Zuul的容错与回退

由图可知,Zuul的Hystrix监控的粒度是微服务,而不是某个API;同时也说明,所有经过Zuul的请求,都会被Hystrix保护起来。

 

(4)关闭项目cloud-register-user,再次访问http://localhost:8023/cloud-register-user/1

页面显示:

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sun Oct 21 11:41:09 CST 2018

There was an unexpected error (type=Internal Server Error, status=500).

TIMEOUT

实验结束,发生异常以上面形式展示,这么显示是不是太low了,接下来,我们看看zuul如何处理这个问题,显得高大上一点。

Zuul实现回退

1.复制项目

复制cloud-register-gateway-zuul微服务修改为cloud-register-gateway-zuul微服务

2.编写zuul回退类

package com.midou.cloud.register.gateway.zuul.fallback;

import com.netflix.hystrix.exception.HystrixTimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

/**
* @author midou
* @description
* @date 2018/10/21 11:54
* @modified by
*/
@Component
public class MyFallbackProvider implements FallbackProvider {
   @Override
   public String getRoute() {
       // 表明是为哪个微服务提供回退,*表示为所有微服务提供回退
       return "*";
   }

   @Override
   public ClientHttpResponse fallbackResponse(Throwable cause) {
       if (cause instanceof HystrixTimeoutException) {
           return response(HttpStatus.GATEWAY_TIMEOUT);
       } else {
           return this.fallbackResponse();
       }
   }

   @Override
   public ClientHttpResponse fallbackResponse() {
       return this.response(HttpStatus.INTERNAL_SERVER_ERROR);
   }

   private ClientHttpResponse response(final HttpStatus status) {
       return new ClientHttpResponse() {
           @Override
           public HttpStatus getStatusCode() throws IOException {
               return status;
           }

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

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

           @Override
           public void close() {
           }

           @Override
           public InputStream getBody() throws IOException {
               return new ByteArrayInputStream("服务不可用,请稍后再试。".getBytes());
           }

           @Override
           public HttpHeaders getHeaders() {
               // headers设定
               HttpHeaders headers = new HttpHeaders();
               MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
               headers.setContentType(mt);
               return headers;
           }
       };
   }
}

添加回退方法后,重复上面实验,看看有什么效果。

异常:

也许可能只有我遇到,先粘贴上来,我遇到这个异常是一个很无脑的问题产生的,希望你不要碰到,如果碰到了跟我的类似存在疑惑,可咨询我。

2018-10-22 09:29:03.885  WARN 7232 --- [nio-8026-exec-4] o.s.c.n.z.filters.post.SendErrorFilter   : Error during filtering



com.netflix.zuul.exception.ZuulException: Forwarding error

at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.handleException(RibbonRoutingFilter.java:189) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]

at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.forward(RibbonRoutingFilter.java:164) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]

at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:111) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]

at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112) ~[zuul-core-1.3.0.jar:1.3.0]

at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193) ~[zuul-core-1.3.0.jar:1.3.0]

at com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:157) ~[zuul-core-1.3.0.jar:1.3.0]

at com.netflix.zuul.FilterProcessor.route(FilterProcessor.java:118) ~[zuul-core-1.3.0.jar:1.3.0]

at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]

Caused by: com.netflix.client.ClientException: null

at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:118) ~[ribbon-loadbalancer-2.2.4.jar:2.2.4]

at org.springframework.cloud.netflix.zuul.filters.route.support.AbstractRibbonCommand.run(AbstractRibbonCommand.java:117) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]

at org.springframework.cloud.netflix.zuul.filters.route.support.AbstractRibbonCommand.run(AbstractRibbonCommand.java:46) ~[spring-cloud-netflix-core-1.4.0.RELEASE.jar:1.4.0.RELEASE]

at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302) ~[hystrix-core-1.5.12.jar:1.5.12]

at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298) ~[hystrix-core-1.5.12.jar:1.5.12]

备注:

在Spring cloud Edgware版本之前,要想回退,需实现ZuulFallBackProvider接口,从Spring cloud Edgware版本之后,实现FallbackProvider接口。

源码获取

1.gitee:https://gitee.com/StarskyBoy/cloud

2.github: https://github.com/StarskyBoy/cloud

获取更多信息,请扫我

Spring Cloud之Zuul(六):Zuul的容错与回退