微服务看门神-Zuul

Zuul网关和基本应用场景

构建微服务时,常见的问题是为系统的客户端应用程序提供唯一的网关。

事实上,您的服务被拆分为小型微服务应用程序,这些应用程序应该对用户不可见,否则可能会导致大量的开发/维护工作。还有一些情况,整个生态系统网络流量可能会通过一个可能影响群集性能的点。

为了解决这个问题,Netflix(微服务的一个主要采用者)创建并开源了它的ZuulZuul是Netflix的基于JVM的路由器和服务器端负载均衡器。后来Spring在Pivotal下已经在其Spring Cloud中对其进行了调整,使我们能够通过简单的步骤轻松有效地使用zuul。

Zuul是一种边缘服务,它支持对多个服务请求的代理。它为您的生态系统提供统一的“前门”,允许任何浏览器,移动应用程序或其他用户界面使用来自多个主机的服务。您可以将Zuul与其他Netflix堆栈组件(如Hystrix)集成以实现容错,使用Eureka进行服务发现,或者使用它来管理整个系统中的路由规则,过滤器和负载平衡。

最重要的是,Spring框架通过Spring boot/cloud很好地适应了所有这些组件。

路由器和过滤器

路由是微服务架构不可或缺的一部分。例如,/可以映射到您的Web应用程序,/api/users映射到用户服务并/api/shop映射到商店服务。

Netflix使用Zuul进行以下操作:

  • 认证
  • 洞察
  • 压力测试
  • 金丝雀测试
  • 动态路由
  • 服务迁移
  • 负载脱落
  • 安全
  • 静态响应处理
  • 主动/主动流量管理

Zuul的规则引擎允许规则和过滤器基本上以任何JVM语言编写,内置支持Java和Groovy。

Zuul组件

Zuul主要有四种类型的过滤器,使我们能够在任何特定事务的请求处理的不同时间线中拦截流量。我们可以为特定的url模式添加任意数量的过滤器。

  • 前置过滤器 - 在路由请求之前调用。
  • 后置过滤器 - 在路由请求后调用。
  • 路由过滤器 - 用于路由请求。
  • 错误过滤器 - 在处理请求时发生错误时调用。

使用不同的过滤器在Zuul内部请求处理流程

过滤器关键概念

关键词

备注

类型Type

定义在路由过程中,过滤器被应用的阶段

执行顺序Execution Order

在同一个Type中,定义过滤器执行的顺序

条件Criteria

过滤器被执行必须满足的条件

动作Action

如果条件满足,过滤器中将被执行的动作

标准过滤器类型

PRE

在请求被路由到源服务器前要执行的过滤器

适用业务场景

  • 认证
  • 选路由
  • 请求日志

ROUTING

处理将请求发送到源服务器的过滤器

POST

在响应从源服务器返回时要被执行的过滤器

  • 对响应增加HTTP 头
  • 收集统计和度量
  • 将响应以流的方式发送回客户端

ERROR

上述阶段中出现错误要执行的过滤器

过滤器样例

public class PreFilter extends ZuulFilter {
​
//  过滤器类型
  @Override
  public String filterType() {
    return "pre";
  }
​
//  过滤器顺序
  @Override
  public int filterOrder() {
    return 1;
  }
​
//  是否加入过滤器流程中
  @Override
  public boolean shouldFilter() {
    return true;
  }
​
//  过滤器运行代码
  @Override
  public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
​
    System.out.println("Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString());
​
    return null;
  }
​
}

netflix zuul实例概述

现在让我们通过使用Zuul创建一个简单而有意义的生态系统来尝试一下。我们将创建下面的组件来演示整个事物:

  • 学生微服务 - 基于spring boot启动的微服务,它只是暴露单个URL以启用一些搜索功能。为简单起见,我们将返回硬编码值,但在现实世界中,我们可以让此服务连接数据库以获取数据。
  • Zuul网关服务 它基于spring boot启动,它将基本上拦截学生服务的所有流量并应用一系列请求过滤器然后路由到底层服务,并在响应服务时再次,它将应用一些响应过滤。由于它是一个网关,我们可以使用过滤器有效地采取许多有趣和有用的操作。 网关服务的一些共同责任是 -
    • 在网关层应用微服务身份验证和安全性以保护实际服务
    • 我们可以通过使一些日志记录在边缘获取有意义的数据和统计数据来实现微服务洞察和监控进入生态系统的所有流量,从而为我们提供准确的生产视图。
    • 动态路由可以根据需要将请求路由到不同的后端群集。
    • 我们可以通过逐渐增加到新集群的流量来进行运行时压力测试,以便在许多情况下衡量性能,例如集群有新的H / W和网络设置,或者部署了新版本的生产代码。
    • 我们可以进行动态负载,即为每种类型的请求分配容量,并删除超出限制的请求。
    • 我们可以应用静态响应处理,即直接在边缘构建一些响应,而不是将它们转发到内部集群进行处理。

技术栈和运行环境

  • Java 1.8和IntelliJIDEA作为开发环境
  • Spring cloud Zuul作为网关代理提供商
  • Spring boot作为应用程序框架
  • Spring Rest用于将微服务暴露为REST
  • Maven作为构建工具

创建学生微服务

按照以下步骤开发学生微服务,稍后将通过zuul代理访问的几个REST端点。稍后我们将研究zuul部分,现在让我们先创建学生服务。

创建Spring Boot项目

创建一个Spring boot项目从spring初始化网站,依赖于Web

将项目解压缩并导入到IDEA中。在此步骤中,使用命令执行maven构建,mvn clean install以便正确下载所有maven依赖项。

添加几个REST端点

我们现在只需向此服务添加一些REST端点,以便稍后测试网关。为此,我们需要通过添加注释添加一个REST控制器@RestController。为简单起见,我们将添加一个模型类Student

完成所有更改后,该类将如下所示。

package com.example.springboostudentservice;
 
import java.util.Date;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
@SpringBootApplication
public class SpringBootStudentServiceApplication
{
    @RequestMapping(value = "/echoStudentName/{name}")
    public String echoStudentName(@PathVariable(name = "name") String name)
    {
        return "hello  <strong style=\"color: red;\">" + name + " </strong> Responsed on : " + new Date();
    }
 
    @RequestMapping(value = "/getStudentDetails/{name}")
    public Student getStudentDetails(@PathVariable(name = "name") String name)
    {
        return new Student(name, "Pune", "MCA");
    }
 
    public static void main(String[] args)
    {
        SpringApplication.run(SpringBootStudentServiceApplication.class, args);
    }
}
 
class Student
{
    String name;
    String address;
    String cls;
 
    public Student(String name, String address, String cls) {
        super();
        this.name = name;
        this.address = address;
        this.cls = cls;
    }
 
    public String getName() {
        return name;
    }
 
    public String getAddress() {
        return address;
    }
 
    public String getCls() {
        return cls;
    }
}

应用程序配置

spring:
  application:
    name: student
server:
  port: 8090

这里我们按属性给这个服务命名,spring.application.name=student我们也定义了默认端口server.port=8090。我们需要覆盖默认端口,因为我们将在localhost中运行不同微服务的多个实例。

验证学生服务

最后使用命令执行maven构建,mvn clean install并通过运行命令将此项目作为spring boot应用程序启动java -jar target\spring-boot-zuulgatway-student-service-0.0.1-SNAPSHOT.jar。现在,一旦服务器启动,转到浏览器并测试端点是否正常工作。

http://localhost:8090/echoStudentName/james

http://localhost:8090/getStudentDetails/james

创建学校微服务

创建过程和学生微服务一样,但是由于服务之间的功能和差异性,我们需要对接口进行简单的修改

添加几个REST断点

我们现在只需向此服务添加一些REST端点,为此,我们需要通过添加注释添加一个REST控制器@RestController。为简单起见,我们将添加一个模型类School

完成所有更改后,该类将如下所示。

@SpringBootApplication
@RestController
public class SpringBootZuulgatewaySchoolServiceApplication {
​
    @RequestMapping(value = "/echoSchoolName/{name}")
    public String echoSchoolName(@PathVariable(name = "name") String name)
    {
        return "hello  <strong style=\"color: green;\">" + name + " </strong> Responsed on : " + new Date();
    }
​
    @RequestMapping(value = "/getSchoolDetails/{name}")
    public School getSchoolDetails(@PathVariable(name = "name") String name)
    {
        return new School(name, "China", "ZheJiang");
    }
​
    public static void main(String[] args) {
        SpringApplication.run(SpringBootZuulgatewaySchoolServiceApplication.class, args);
    }
​
}
​
class School
{
    String name;
    String address;
    String cls;
​
    public School(String name, String address, String cls) {
        super();
        this.name = name;
        this.address = address;
        this.cls = cls;
    }
​
    public String getName() {
        return name;
    }
​
    public String getAddress() {
        return address;
    }
​
    public String getCls() {
        return cls;
    }
}

应用程序配置

现在打开application.properties文件并添加这些条目。

spring:
  application:
    name: school
server:
  port: 8100

这里我们按属性给这个服务命名,spring.application.name=school我们也定义了默认端口server.port=8100`。我们需要覆盖默认端口,因为我们将在localhost中运行不同微服务的多个实例。

验证学校服务

最后使用命令执行maven构建,mvn clean install并通过运行命令将此项目作为spring boot应用程序启动java -jar target\spring-boot-zuulgatway-school-service-0.0.1-SNAPSHOT.jar。现在,一旦服务器启动,转到浏览器并测试端点是否正常工作。

http://localhost:8100/echoSchoolName/学军中学

http://localhost:8100/getSchoolDetails/学军中学

现在我们将使用Zuul创建实际的网关服务。

创建Zuul网关服务

这将是一个基于Spring boot的微服务,但它有一个特殊的功能。它将使用zuul创建一个代表学生服务的API网关。稍后我们可以添加任意数量的微服务,如学生服务,学校服务并能够创建一个强大的微服务生态系统。

创建String Boot项目

spring初始化网站创建一个具有Zuul依赖关系的Spring boot项目。

将项目作为现有maven项目解压缩并导入IDEA。在此步骤中,使用命令执行maven构建,mvn clean install以便正确下载所有maven依赖项。

启用Zuul服务

现在@EnableZuulProxysrc文件夹中的Spring启动应用程序类中添加注释。使用此批注,此工件将像Zuul服务代理一样运行,并将启用API网关层的所有功能,如前所述。然后我们将添加一些过滤器和路由配置。

import com.example.zuuldemo.filters.ErrorFilter;
import com.example.zuuldemo.filters.PostFilter;
import com.example.zuuldemo.filters.PreFilter;
import com.example.zuuldemo.filters.RouteFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
​
@SpringBootApplication
@EnableZuulProxy
public class ZuuldemoApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(ZuuldemoApplication.class, args);
    }
​
    @Bean
    public PreFilter preFilter() {
        return new PreFilter();
    }
    @Bean
    public PostFilter postFilter() {
        return new PostFilter();
    }
    @Bean
    public ErrorFilter errorFilter() {
        return new ErrorFilter();
    }
    @Bean
    public RouteFilter routeFilter() {
        return new RouteFilter();
    }
​
}
​

Zuul应用配置

打开application.yml并在下面添加条目

zuul:
  routes:
    student:
      url: http://localhost:8090
    school:
      url: http://localhost:8100
server:
  port: 8080

这里zuul.routes.student.url将路由所有流量以请求/student到实际的学生服务服务器。zuul.routes.school.url将路由所有流量以请求/school到实际的学校服务服务器 server.port - 需要覆盖默认端口,因为我们将在localhost中运行不同微服务的多个实例。

添加Zuul过滤器

正如我们已经描述了zuul组件,我们将添加一些过滤器,Zuul支持4种类型的过滤器,即prepostrouteerror。在这里,我们将创建每种类型的过滤器。

要编写过滤器,我们基本上需要执行以下步骤:

  • 需要扩展 com.netflix.zuul.ZuulFilter
  • 需要重写filterTypefilterOrdershouldFilterrun方法。这里的filterType方法只能返回四个String中的任何一个 - pre/post/route/error。降低此值后,过滤器将像特定过滤器一样运行。
  • run method是根据我们的要求放置滤波器逻辑的地方。
  • 此外,我们可以根据需要添加任意数量的任何特定过滤器,这种情况filterOrder将用于确定该过滤器执行阶段该文件管理器的顺序。

前置过滤器代码 - 我们将添加以下预过滤器。目前,过滤器除了println用于测试目的之外什么都不做。但实际上那些功能足以完成前面提到的许多重要方面。

package com.example.springbootzuulgateway.filters;
​
import javax.servlet.http.HttpServletRequest;
​
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
​
public class PreFilter extends ZuulFilter {
​
  @Override
  public String filterType() {
    return "pre";
  }
​
  @Override
  public int filterOrder() {
    return 1;
  }
​
  @Override
  public boolean shouldFilter() {
    return true;
  }
​
  @Override
  public Object run() {
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
​
    System.out.println("Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString());
​
    return null;
  }
​
}

后置过滤器

package com.example.springbootzuulgateway.filters;

import com.netflix.zuul.ZuulFilter;

public class PostFilter extends ZuulFilter {

  @Override
  public String filterType() {
    return "post";
  }

  @Override
  public int filterOrder() {
    return 1;
  }

  @Override
  public boolean shouldFilter() {
    return true;
  }

  @Override
  public Object run() {
   System.out.println("Inside Response Filter");

    return null;
  }

}

路由过滤器

package com.example.springbootzuulgateway.filters;

import com.netflix.zuul.ZuulFilter;

public class RouteFilter extends ZuulFilter {

  @Override
  public String filterType() {
    return "route";
  }

  @Override
  public int filterOrder() {
    return 1;
  }

  @Override
  public boolean shouldFilter() {
    return true;
  }

  @Override
  public Object run() {
   System.out.println("Inside Route Filter");

    return null;
  }

}

错误过滤器

package com.example.springbootzuulgateway.filters;

import com.netflix.zuul.ZuulFilter;

public class ErrorFilter extends ZuulFilter {

  @Override
  public String filterType() {
    return "error";
  }

  @Override
  public int filterOrder() {
    return 1;
  }

  @Override
  public boolean shouldFilter() {
    return true;
  }

  @Override
  public Object run() {
   System.out.println("Inside Route Filter");

    return null;
  }

}

5.5。注册zuul过滤器

创建要自动注册和启用的这些过滤器的bean定义。

@Bean
    public PreFilter preFilter() {
        return new PreFilter();
    }
    @Bean
    public PostFilter postFilter() {
        return new PostFilter();
    }
    @Bean
    public ErrorFilter errorFilter() {
        return new ErrorFilter();
    }
    @Bean
    public RouteFilter routeFilter() {
        return new RouteFilter();
    }

Netflix zuul示例演示

所以我们启用了Zuul,添加了所需的配置并开发了过滤器。所以我们可以做基本的测试来理解整个事情。

使用命令执行maven构建,mvn clean install并通过运行命令将此项目作为spring boot应用程序启动java -jar target\spring-boot-zuulgateway-0.0.1-SNAPSHOT.jar

现在,一旦服务器启动,转到浏览器并通过访问学生服务名称和学校服务来测试端点是否正常工作,即/student/school

http://localhost:8080/student/echoStudentName/james

http://localhost:8080/school/echoSchoolName/学军学校

总结

这就是netflix zuul过滤器示例。我建议你自己做,通过代理添加一些更多的底层服务和路由请求,应用不同类型的过滤器并在过滤器中添加真正的逻辑。

链接: https://pan.baidu.com/s/1zpUBTCDNVHO4s8TAIOxKVA 提取码: 8v7w

请在评论部分将您的问题提交给我。

快乐学习!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励