文章目录

  • 六、Zuul
  • 1、简要概述
  • 2、Zuul作用
  • 3、Zuul进行地址转换和负载均衡
  • 4、过滤器
  • <1>、ZuulFilter
  • <2>、生命周期
  • <3>、自定义过滤器
  • <4>、Zuul负载均衡和熔断


六、Zuul

1、简要概述

zuul spring_zuul spring


不使用Zuul的开发架构是:

zuul spring_负载均衡_02

2、Zuul作用

加入Zuul之后的架构是:

zuul spring_.net_03


不管是来自于客户端(PC或移动端)的请求,还是服务自己内部调用。一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现鉴权、动态路由等等操作。Zuul就是我们服务的统一入口。

3、Zuul进行地址转换和负载均衡

在父工程下创建一个miscroservicecloudzuulgateway9527的maven工程
在pom文件中添加如下依赖:

<dependencies>
        <!--zuul路由网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>    
        <!--actuator监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--hystrix容错-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--日常标配-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>SpringCloud</groupId>
            <artifactId>miscroserviceapi</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
            <version>1.2.6.RELEASE</version>
        </dependency>
    </dependencies>

编写主启动类:

package springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;


@SpringBootApplication
@EnableZuulProxy
public class Zuul_9527_StartSpringCloudApp {

    public static void main(String[] args) {
        SpringApplication.run(Zuul_9527_StartSpringCloudApp.class, args);
    }
}

以kv形式配置路由规则,k就是路由id,path就是所匹配的路径,最终让此端口的这一路径会先通过网关然后才能访问微服务,

server:
  port: 9527
zuul:
  prefix: /example
#  ignored-services: miscroservicecloud-dept
  ignored-services: "*"
  routes:
    mydept.serviceId: miscroservicecloud-dept
    mydept.path: /mydept/**

我们可以发现,现在已经不用再访问本来的端口访问到数据了,而是经过了网关去转发请求地址,来到了9527。
但是有一个问题,如果以后的微服务地址发生了变化,或者启动了多台集群需要我们配置负载均衡,那么我们就要在zuul的依赖中引入Eureka客户端的依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

然后进行相关的配置

server:
  port: 9527
spring:
  application:
    name: miscroservice-cloud-zuul-gateway
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka 
    instance:
      instance-id: gateway-9527.com
      prefer-ip-address: true

info:
  app.name: miscrocloud
  company.name: www.cloud.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$
zuul:
  prefix: /example
#  ignored-services: miscroservicecloud-dept
  ignored-services: "*"
  routes:
    mydept.serviceId: miscroservicecloud-dept
    mydept.path: /mydept/**

当一个request请求过来之后,先进行端口和serviceID的匹配,匹配到之后将原服务转发到zuul网关的服务 ,但服务本身没有地址,因此要拉取Eureka的INSTANCE列表,获取具体的路径地址,然后通过负载均衡算法,这就是面向服务的路由,内部同时实现了负载均衡和地址转发。

4、过滤器

Zuul作为网关中的一个重要功能,母目的就是要实现请求的鉴权。但是这个动作我们往往是通过Zuul提供的过滤器来实现的。

<1>、ZuulFilter

ZuulFilter是过滤器的最高级的父类,其中有四个最重要的方法

public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {

    abstract public String filterType();//过滤器类型

    abstract public int filterOrder();//过滤器顺序
    
    boolean shouldFilter();// 来自IZuulFilter,要不要过滤

    Object run() throws ZuulException;// IZuulFilter,过滤逻辑
}
  • shouldFilter:返返回的是一个boolean值,判断该过滤器是否要执行,返回true则执行,反之则不执行。
  • run:过滤器的具体业务逻辑
  • filterType:返回的是字符串,代表是过滤器的类型,其中包括四种类型:
  • pre:请求在被路由之前执行
  • route:路由请求时调用
  • post:在routing和errror过滤器之后调用
  • error:处理请求时发生错误调用
  • filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
<2>、生命周期

zuul spring_zuul spring_04


正常流程:

请求到达首先会经过pre类型过滤器,然后到达routing类型,进行路由请求就到达真正的服务提供者执行请求,返回结果后,会先经过post过滤器。之后返回响应。

异常流程:

整个过程中,pre类型或者routing类型过滤器出现异常,都会直接进入error过滤器,待error型过滤器处理完毕后,将请求交给POST过滤器,最终返回给用户。

如果是error过滤器自己出现异常,最终也会进入POST过滤器,之后返回。

如果是post过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求不会再到达post类型的过滤器。

<3>、自定义过滤器
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class LoginFilter extends ZuulFilter {

    @Override
    public String filterType() {//过滤器种类
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {//过滤器优先级
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {//判断是否过滤
        return true;
    }

    @Override
    public Object run() throws ZuulException {//过滤逻辑,登录拦截
        //获取请求上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        //获取request
        HttpServletRequest request = ctx.getRequest();
        //获取请求参数
        String take = request.getParameter("access-token");
        //判断是否存在
        if (StringUtils.isBlank(take)) {
            //不存在,未登录,就拦截
            ctx.setSendZuulResponse(false);
            //返回403
            ctx.setResponseStatusCode(HttpStatus.FORBIDDEN.value());
        }
        return null;
    }
}

运行进行测试,输入原来的地址,出现403禁止访问的错误,是因为没有按照之前的自定义过滤器所编写的规则,同时提交一个请求参数,由于我们没有具体的业务实现,所以填写什么路由规则都可以

<4>、Zuul负载均衡和熔断

Zuul中默认已经集成了Ribbon负载均衡和Hystix熔断机制。但所有的超时策略都是默认值,比如熔断超时时间只有1s,很容易就触发了。因此建议我们手动进行配置:

ribbon:
  ReadTimeout: 60000
  ConnectTimeout: 60000
  
hystrix:
  command:
    default:
      execution:
        isolution:
          thread:
            timeoutInMilliseconds: 2000