您现在的位置是:首页 >技术交流 >【每天学习一点点】微服务网关、zuul、spring cloud gateWay网站首页技术交流

【每天学习一点点】微服务网关、zuul、spring cloud gateWay

to方圆圆 2023-05-21 12:00:02
简介【每天学习一点点】微服务网关、zuul、spring cloud gateWay

一、微服务网关

1. 为什么需要网关

在微服务开发中,一个大型一体化系统常常具有多个系统,比如临床试验一体化系统,具备财务系统、药房系统、伦理系统等。而现在的开发又是前后端分离的,因此我们访问一个前端地址,可以访问到不同的系统的数据,因此必须在前端中按钮指定系统的url,但是每一个系统的部署ip和port端口不同,如果全部维护在前端信息中,第一个是不安全,这样就把我们的系统信息给暴露出去了;第二个是不容维护,如果后续系统越来越多,前端维护的内容也就越来越多,因此需要使用一个网关层,同时网关也不仅仅是作路由的转发、也可以做一些拦截功能:是否具备权限点、是否登陆、是否限流等系统共性验证。

2. 业界常用网关层框架

  1. zuul ,netflix开发的网关框架
  2. spring cloud gateway

3. api网关应该具备的功能

  1. 异步IO、长链接
  2. 过滤器链条:pre、post
  3. ribbon负载均衡
  4. 服务发现
  5. 动态路由
  6. 熔断器
  7. 监控追踪
  8. 多种协议

二、zuul

Zuul 是 Netflix 开源的一个基于 Java 的 API 网关服务,可以处理所有的微服务请求,并提供了许多功能,包括动态路由、安全性、监控和追踪等。Zuul 可以将所有的请求路由到多个后端服务器上,并且可以通过过滤器来处理请求和响应。

下面是 Zuul 的一些特点和优势:

  1. 动态路由:Zuul 支持动态路由,可以根据请求的 URL 将请求路由到不同的微服务中,从而实现负载均衡和容错处理。

  2. 服务发现:Zuul 可以与 Eureka 或 Consul 等服务注册中心集成,从而可以自动发现微服务的地址和端口。

  3. 过滤器:Zuul 提供了强大的过滤器机制,可以对请求进行预处理和后处理。开发人员可以编写各种类型的过滤器,包括前置过滤器、后置过滤器、路由过滤器和错误过滤器等。

  4. 安全性:Zuul 可以通过 OAuth、JWT 和 HTTP 基本认证等机制来保护微服务的安全性。

  5. 监控和追踪:Zuul 可以通过与 Zipkin 集成来实现请求的跟踪和监控。还可以使用 Hystrix Dashboard 来监视请求的性能和故障。

总的来说,Zuul 是一个强大的 API 网关,可以帮助开发人员管理和监控所有的微服务请求。通过使用 Zuul,开发人员可以减少代码重复,提高系统的可维护性和可扩展性。

2.1 动态路由

一个网关层最不可或缺的就是动态路由了,比如请求一个 http:网关地址//user/add这个地址,经过网关层肯定需要将该请求地址进行路由到正确的服务地址了,这个和nginx的请求匹配类似。

2.1.1 前缀匹配(Ant 风格)

 zuul:
   routes:
     user-service:
       path: /users/**
       serviceId: user-service

上述/users/**这个users就是前缀,如果匹配了,则会反向代理到serviceId的服务上,
上述配置会将以 /users/ 开头的请求路由到 user-service 微服务上,并去掉请求路径中的 /users/ 前缀。

2.1.2 正则匹配

 zuul:
   routes:
      user-service:
      	path: /api/v1/(users|clients)/.*
      	serviceId: user-service

也就是说path上面是可以使用正则的

2.1.3 地址重写

 zuul:
   routes:
      user-service:
      	path: /api/v1/(users|clients)/.*
      	serviceId: user-service
   rewrite:
      user-service:
      	paths: /api/v1/**
      	to: /user-service/api/v1

rewrite和routes是同级,也就说,会将/api/v1/** 替换成/user-service/api/v1进行转发

2.1.3 参数说明

  1. StripPrefix: 是否过滤请求路径的前缀
  2. zuul:
    ignored-patterns: //admin/
    上述配置会忽略所有包含 /admin/ 的路径,这些请求将不会被 Zuul 拦截和处理。
  3. url: 请求地址,真实的地址,配置该项则不会走服务发现

2.1.4 问题

我们这样看感觉和nginx作用类似的啊,路由规则也大差不差,为什么不使用nginx作为网关进行路由转发呢?

具体看下一节

2.2 服务发现

Zuul 可以与 Eureka 或 Consul 等服务注册中心集成,从而可以自动发现微服务的地址和端口。

在上面可以知道我们第一个前缀匹配其实并没有指定对应的服务地址的ip和端口,只是指定了对应的serverId。而这个serverId就是注册中心的服务标识。

这样如果匹配了/users地址,这样用户服务如果部署了多个,就可以从注册中心负载均衡拿到对应的一个进行转发。这样在扩展服务或者下线对应服务就不需要改动网关层的配置信息。做到自动发现微服务的地址和端口,nginx是没有这样的功能的。

2.2.1 zuul如何继承服务注册中心

2.2.1.1 集成nacos
  1. 在zuul的服务、api服务引入对应maven配置
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

  1. 在 应用配置文件中添加nacos相关配置:
spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

  1. 再zull中进行配置
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

在以上配置完成后,当应用启动时,它就会自动向 Nacos 注册,并将自己的服务 ID、主机名和端口号等信息上报给 Nacos Server。同时,Zuul 也会从 Nacos 中获取可用的服务列表,并根据路由规则选择其中一个进行转发。

在使用 Nacos 进行服务发现时,Zuul 会使用 Ribbon 进行负载均衡,从而实现高可用和容错性。因此,如果你使用了服务发现来进行负载均衡,建议在后端服务中添加 Ribbon 的依赖,并对其进行配置,以获得更好的负载均衡效果。

2.2.2 引入ribbon进行负载均衡

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

ribbon:
eureka:
enabled: true
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
listOfServers: http://localhost:8080,http://localhost:8081
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

2.2.3 问题:使用了nacos作为注册中心,还需要引入ribbon吗,nacos注册中心不是自带了服务端的负载均衡吗

当使用 Nacos 作为服务注册中心时,由于 Nacos 自带了服务端的负载均衡功能,因此不需要额外引入 Ribbon 进行客户端负载均衡。

在使用 Nacos 作为服务注册中心时,可以通过向 Nacos 注册中心注册多个服务实例,从而实现负载均衡和容错性。Nacos 会自动将请求路由到可用的服务实例,并实现故障转移和自动恢复等功能。

因此,在使用 Nacos 作为服务注册中心时,如果只是进行简单的服务调用或者使用 Spring Cloud Gateway 进行路由转发,通常无需引入 Ribbon 进行客户端负载均衡。但是,如果你需要对服务实例进行更加细粒度的控制,如指定特定的服务实例、优先使用某些服务实例等,则可以考虑引入 Ribbon 等客户端负载均衡器,以实现更加灵活的服务消费方式。

3. zuul的过滤器

Zuul 作为一个 API 网关,提供了多种过滤器来实现请求的前置、后置处理和路由转发。这些过滤器可以在请求进入 Zuul 或者离开 Zuul 时执行,从而实现如鉴权、限流、日志记录、安全控制等功能。

常用的 Zuul 过滤器包括:

  1. Pre 过滤器:在请求被路由到目标服务之前执行,主要用于实现身份认证、参数校验、请求限流等功能。常见的 Pre 过滤器有:

     AuthenticationFilter:用于对请求进行身份验证和权限校验。
     RateLimiterFilter:用于实现请求限流和防止恶意攻击。
     AccessLogFilter:用于记录请求日志和监控接口性能。
    
  2. Routing 过滤器:用于将请求发送到目标服务,通常是通过 HTTP 客户端或者负载均衡器实现的。常见的 Routing 过滤器有:

     SimpleHostRoutingFilter:用于将请求转发到指定的目标服务。
     RibbonRoutingFilter:使用 Netflix Ribbon 进行客户端负载均衡,并将请求转发到选择的服务实例。
     SendForwardFilter:用于将请求转发到其他 URL 或者资源。
    
  3. Post 过滤器:在响应返回给客户端之前执行,用于对响应进行加工和处理。常见的 Post 过滤器有:

     AddResponseHeaderFilter:用于添加响应头信息。
     ModifyResponseBodyFilter:用于修改响应体信息。
     SendErrorFilter:用于处理发生错误时的情况。
    
  4. Error 过滤器:在请求发生错误时执行,用于对异常进行处理和记录。常见的 Error 过滤器有:

     DefaultErrorFilter:默认的错误过滤器,用于处理所有未被其他过滤器处理的异常。
     SimpleHostRoutingErrorFilter:用于处理请求转发时发生的异常。
    

3.1 使用例子

在实际使用中,可以通过继承 Zuul 提供的 Filter 抽象类,并重写其 run() 方法来实现自定义的过滤器。例如:

public class MyPreFilter extends ZuulFilter {

    @Override
    public String filterType() {
        // 指定过滤器类型为前置过滤器
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        // 指定过滤器优先级为 0
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        // 判断当前请求是否需要过滤
        return true;
    }

    @Override
    public Object run() {
        // 在此处进行过滤逻辑的实现
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String token = request.getParameter("token");
        if (token == null) {
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            context.setResponseBody("Token is required.");
        }
        return null;
    }
}

上述代码中,继承了 ZuulFilter 抽象类,并实现了其中的 filterType()、filterOrder()、shouldFilter() 和 run() 方法,以完成自定义的 Pre 过滤器。在 shouldFilter() 方法中可以根据具体的场景返回是否需要过滤当前请求,在 run() 方法中则可以编写过滤逻辑的实现。

4. zuul安全性

Zuul 作为 API 网关,是应用程序和用户之间的入口,对于整个系统的安全性具有至关重要的作用。以下是提高 Zuul 安全性的一些常见措施:

  1. 身份认证和授权:使用 OAuth2、JWT 等机制实现用户身份认证和授权,禁止未经授权的访问。可以通过自定义 Pre 过滤器,检查请求中的 token 或用户名密码等信息进行验证。

  2. 敏感信息过滤:在请求和响应中过滤敏感信息,如密码、手机号码等,防止泄露。可以通过自定义 Pre 和 Post 过滤器,对请求数据和响应数据进行加工和处理。

  3. 限流和防刷:使用限流算法和防刷策略防止恶意攻击和异常流量对系统造成影响。可以通过自定义 Pre 过滤器和使用第三方库(如 Guava、Redis 等)来实现限流和防刷功能。

  4. 请求日志记录:记录请求的详细信息和响应结果,便于系统监控和排错。可以通过自定义 Pre 和 Post 过滤器,记录请求和响应信息,并使用日志框架(如 log4j、logback 等)将其输出到指定的文件或者中心化日志管理平台。

  5. SSL/TLS 加密:使用 SSL/TLS 协议对通信数据进行加密,保护数据传输的安全性。可以通过配置 Zuul 的 SSL 证书和相关参数来实现。

  6. 安全测试和漏洞扫描:定期进行安全测试和漏洞扫描,发现并修复潜在的安全弱点和漏洞。可以使用第三方工具(如 Nessus、Burp Suite 等)进行安全测试和漏洞扫描,或者委托专业机构进行安全审计和评估。

需要注意的是,Zuul 本身并不提供完整的安全性解决方案,开发者需要根据具体场景和需求,选择合适的安全措施来增强系统的安全性。

5. 监控和追踪

在 Zuul 上实现监控和追踪可以帮助我们更好地了解系统的运行状态和性能瓶颈,提高系统的可靠性和可维护性。以下是几种常见的监控和追踪技术:

  1. 日志监控:Zuul 通过使用 Spring Boot 自带的 Actuator 模块,可以方便地暴露各项系统指标和健康检查信息。同时,还可以配置日志框架输出详细的请求日志和错误日志,以便于排查问题。可以通过配置 application.yml 或者使用 JMX 等方式对 Actuator 进行调整。

  2. 分布式跟踪:在分布式系统中,由于请求会经过多个服务节点,因此需要使用分布式跟踪技术来实现请求链路的追踪和性能监控,帮助我们定位慢请求和异常情况。常用的分布式跟踪工具包括 Zipkin、SkyWalking 等。

  3. 指标监控:使用指标监控工具,如 Prometheus、Grafana 等,可以对系统的各项性能指标进行实时监控和可视化展示,并通过警报机制及时发现系统的异常情况,支持快速响应和修复。

  4. 调用链路追踪:通过配置调用链路追踪工具,如 Jaeger、Pinpoint 等,可以实现对请求调用链路的追踪和分析,帮助我们发现慢请求并进行优化。

在使用以上技术时,需要注意以下几点:

需要对系统性能指标进行细致的监控,并定制合适的警报机制和自动化任务以应对不同的异常情况。

在使用分布式跟踪和调用链路追踪工具时,需要对系统服务节点进行适当修改和配置。同时,需要保证工具的稳定性和可靠性,以避免给系统带来额外风险。

监控和追踪技术并不能完全保障系统的安全性和健壮性,还需要结合其他安全策略和措施来实现整个系统的安全和可靠运行。

三. zuul2 特性

3.1 zuul1 缺点

在第2点进行介绍的时候,该zuul1的框架还存在诸多问题

  1. 仅仅只支持http调用其他服务
  2. Zuul 1 的底层实现是使用 Servlet API 和 Apache HttpClient,而不是 Netty。具体来说,Zuul 1 使用了 Spring MVC 框架作为 Servlet 容器,处理 HTTP 请求
  3. 也就是说zuul 1是使用BIO,性能太差。
  4. 只有同步请求,调用其他的服务只能同步,没有异步
  5. 使用io形式为短链接,也就是调用一次,后续还需要创建tcp链接

3.2 zuul 2优点

Zuul 2 是 Netflix 提供的第二代网关,相比于第一代 Zuul,它提供了更多的特性和改进。以下是 Zuul 2 的一些主要特性:

  1. 异步 IO 和长连接:Zuul 2 使用 Netty 来处理请求,支持异步 IO 和长连接技术,可以大幅提升并发性能和吞吐量,同时减少资源消耗。

  2. 新的插件系统:Zuul 2 的插件系统采用基于注解的方式来实现,可以简化插件开发和管理,同时支持动态加载和卸载插件。

  3. 多种协议支持:Zuul 2 支持 HTTP、WebSocket、TCP 等多种协议的转发,可以满足不同业务场景下的需求。

  4. 路由配置文件优化:Zuul 2 的路由配置文件采用 YAML 格式编写,可以更加直观和易读,并且支持动态刷新,可以避免重启服务的情况下更新配置。

  5. 新的过滤器机制:Zuul 2 的过滤器机制采用基于 SPI 的方式来实现,可以灵活选择过滤器链和顺序,并支持动态添加和删除过滤器。

  6. 支持 OAuth 2.0 和 JWT:Zuul 2 内置了 OAuth 2.0 和 JWT 的支持,可以方便地实现安全认证和授权功能。

  7. 插桩(Instrumentation)支持:Zuul 2 支持对请求和响应的插桩,可以在请求处理过程中记录和收集性能指标和日志信息。

  8. 多种部署方式:Zuul 2 可以与 Spring Cloud 集成,支持微服务架构和容器化部署方式,同时也可以单独部署或者与其他网关配合使用。

总的来说,Zuul 2 是一个强大而灵活的网关,具有高性能、可扩展性和丰富的特性。这些特性可以帮助开发者更加轻松地搭建和维护分布式系统,并提供更好的性能和安全保障。

四、Spring cloud gateway

Spring Cloud Gateway 是 Spring Cloud 生态中的一个 API 网关服务,它基于 Spring 5、Project Reactor 和 Spring Boot 2 技术栈开发,具有高性能、易扩展、灵活配置等特点。Spring Cloud Gateway 提供了强大的路由功能和过滤器机制,可以对所有进入网关的请求进行统一管理、控制和处理,从而为微服务架构提供了统一的入口和出口。

以下是 Spring Cloud Gateway 的一些主要特性:

  1. 与 Spring Boot 高度集成,易于使用和扩展;
  2. 基于 Netty 和 Project Reactor 实现,具有优秀的性能和响应速度;
  3. 支持动态路由、负载均衡、断路器等功能,能够实现复杂的路由策略;
  4. 支持多种协议,包括 HTTP、WebSockets、TCP 等;
  5. 可以通过自定义过滤器实现诸如鉴权、日志、限流等功能;
  6. 提供了丰富的监控和统计功能,方便对网关进行监测和管理。
  7. Spring Cloud Gateway 基于 Reactive 编程模型,使用 Project Reactor 来处理异步操作和事件驱动,因此可以实现非常高效的请求处理和快速的响应时间。同时,Gateway 还支持 WebFlux 应用程序模型,使其可以无缝地集成到 Spring WebFlux 应用程序中,从而更好地支持异步和非阻塞的编程模式。

总之,Spring Cloud Gateway 是一个功能强大、易扩展、高性能的 API 网关服务,可以为微服务架构提供统一的入口和出口,并提供了丰富的路由、过滤器、监控等功能,是构建基于 Spring Cloud 的微服务应用程序的不二选择。

4.1 gateway 和zuul2区别

最大的区别就是gateway使用了spring webFlux反应式编码,Spring WebFlux 是一个支持反应式编程的 Web 框架,它主要通过 Reactor 库和 Reactive Streams 规范来实现反应式编程模型。在 Spring WebFlux 中,我们通常会使用 Mono 和 Flux 这两种类型的反应式流来处理请求和响应,从而实现高并发、低延迟的 Web 应用程序。

服务提供者

@Service
public class MyService {
    public Mono<String> getData(String id) {
        return Mono.just("data");
    }
}

服务消费者

java
MyService service = new MyService();
Mono<String> result = service.getData("id");
result.subscribe(str -> System.out.println(str));

这里通过subscribe进行回调接口处理。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。