Zuul

ZuulNetflix开源的一个边缘服务框架,主要用于构建API网关。 它提供了一种路由请求到后端服务的方式,并且可以添加安全、监控和弹性等功能。 Zuul可以作为微服务架构中的一个核心组件,用于处理所有进入和离开系统的请求。 Zuul自动集成了Ribbon,天生就有负载均衡。

主要作用

  • 路由:根据请求的URLHTTP方法或其他自定义规则将请求转发给正确的微服务。
  • 过滤器:可以在请求到达微服务之前或响应返回客户端之前执行一些操作,如身份验证、监控、负载均衡等。
  • 容错:通过内置的Hystrix客户端实现断路器模式,提高系统的稳定性和响应性。
  • 静态响应:在某些情况下,可以直接返回预定义的响应,而无需调用后端服务。

Zuul通常与Spring Cloud框架结合使用,以构建高度可扩展和健壮的微服务网关。

Zuul截止Spring CloudH.SR12版本之后就彻底从官网移除了,假如你这时候还想使用Zuul,需要注意版本,SpringBoot版本也需要注意,不可以高于2.3.12.RELEASE

通信原理

Zuul是通过Servlet来实现的(Servlet会为每个请求绑创建一个线程,而线程上线文切换,内存消耗大), Zuul通过自定义的ZuulServlet(类似于Spring MVCDispatcherServlet)来对请求进行控制(一系列过滤器处理Http请求)。

所有的Request都要经过ZuulServlet的处理,三个核心的方法preRoute()route()postRoute()Zuulrequest处理逻辑都在这三个方法里,ZuulServlet交给ZuulRunner去执行。 ZuulRunner直接将执行逻辑交由FilterProcessor处理,ZuulServletZuulRunnerFilterProcessor都是单例。

FilterProcessorfilter的处理逻辑

  • 根据Type获取所有输入该TypefilterList<ZuulFilter> list
  • 遍历该list,执行每个filter的处理逻辑,processZuulFilter(ZuulFilter filter)
  • RequestContext对每个filter的执行状况进行记录,此处的执行状态主要包括其执行时间、以及执行成功或者失败,若失败则对异常封装后抛出。
  • Zuul框架对每个filter的执行结果都没有太多的处理,上一个filter的执行结果没交给下一个将要执行的filter,仅记录执行状态,如果执行失败抛出异常并终止执行。

过滤器的功能

  • 身份验证和安全性:确定每个资源的身份验证要求并拒绝不满足这些要求的请求。
  • 洞察和监控:在边缘跟踪有意义的数据和统计数据,以便为我们提供准确的生产视图。
  • 动态路由:根据需要动态地将请求路由到不同的后端群集。
  • 压力测试:逐渐增加群集的流量以衡量性能。
  • 负载分配:为每种类型的请求分配容量并删除超过限制的请求。
  • 静态响应处理:直接在边缘构建一些响应,而不是将它们转发到内部集群。

生命周期(四类过滤)

  • PRE:在请求被路由之前调用。可在集群中选择请求的微服务、认证鉴权,限流等。
  • ROUTING:将请求路由到微服务。可构建发送给微服务的请求,并使用Apache HttpClient或 Ribbon请求微服务,现在也支持OKHTTP。
  • POST:在路由到微服务以后执行。可在这种过滤中处理逻辑,如收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。可做全局异常处理。

使用

引用依赖

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

路由配置

Zuul在不添加配置的情况下,默认就是允许通过服务名称来调用其他服务的,Zuul也可以指定url来访问

通过url来访问,不通过注册中心来转发请求。

zuul:
  routes:
    test:    # 自定义的路由名称
      path: /test/**  # 匹配路径
      url: http://127.0.0.1:8001  # 请求地址

配置说明

zuul:
  prefix: /haohaodayouxi # 代表的是所有的路由前缀
  ignored-services: "*"   # 关闭具体的服务名称访问,"*" 代表全部。
  ignoredPatterns: /**/system/**   # 指定哪些请求 不允许进行路由。
  routes: # 路由映射配置
    test:
      path: /test/**             # 匹配路径
      serviceId: test-service    # 注册中心的服务名称
      stripPrefix: false         # 针对单个路由是否要用前缀访问的设置,默认是true

注解启动

@SpringBootApplication
@EnableZuulProxy // 开启网关功能
public class TestZuulApplication {

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

    /**
     * 配置动态路由规则
     * @return
     */
    @Bean
    public PatternServiceRouteMapper getPatternServiceRouteMapper() {
        return new PatternServiceRouteMapper("(?<name>^.+)", "${name}");
    }
}

自定义过滤器

@Component
public class TokenFilter extends ZuulFilter {

    /**
     * 拦截类型,4种类型 pre route error post
     */
    @Override
    public String filterType() {
        //  FilterConstants.PRE_TYPE;
        //  FilterConstants.ROUTE_TYPE;
        //  FilterConstants.ERROR_TYPE;
        //  FilterConstants.POST_TYPE;
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 该过滤器在所有过滤器的执行顺序值,值越小,越前面执行
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否拦截
     */
    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        // RequestContext ctx = RequestContext.getCurrentContext();
        // ctx.getBoolean("isOk");
        HttpServletRequest request = ctx.getRequest();
        String requestURI = request.getRequestURI();
        // 排除拦截的url
        if (requestURI.equals("/test/token")) {
            return false;
        }
        return true;
    }

     /**
      * 过滤器具体的业务逻辑
      */
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String token = request.getParameter("token");
        // ctx.set("isOk",true); // 可以在上下文里面设置一个key,在下一次拦截时,就可以获取到
        if (null == token) {
            ctx.setResponseBody("token is null");
            ctx.setResponseStatusCode(400);
            ctx.setSendZuulResponse(false);
            return null;
        }
        if (!"123456".equals(token)) {
            ctx.setResponseBody("token is error");
            ctx.setResponseStatusCode(400);
            ctx.setSendZuulResponse(false);
            return null;
        }
        ctx.setSendZuulResponse(true);
        return null;
    }
}

关闭过滤器

zuul:
  TokenFilter:
    pre:
      disable: true # 关闭前置过滤器

超时时间设置

如果使用@EnableZuulProxy,则可以使用代理路径上传文件,只要文件很小,它应该可以工作。

对于大文件接口访问慢,这时候需要设置超时时间

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 60000
ribbon:
  ConnectTimeout: 3000
  ReadTimeout: 60000

如果想通过Zuul代理的请求,配置套接字超时和读取超时

zuul:
  host:
    connect-timeout-millis: 40000
    socket-timeout-millis: 40000
    connection-request-timeout-millis: 40000

results matching ""

    No results matching ""