当前位置 : 首页 » 文章分类 :  开发  »  Spring-Cloud-Netflix-Zuul

Spring-Cloud-Netflix-Zuul

Spring Cloud Zuul 笔记
Zuul 是 Netflix 开源的微服务网关,它可以和 Eureka, Ribbon, Hystrix 等组件配合使用。Zuul 的核心是一系列的过滤器,这些过滤器帮助我们实现路由转发和认证等功能。

Netflix / zuul
https://github.com/Netflix/zuul


API网关选型

为什么需要API网关?

微服务架构中,如果没有 API 网关,鉴权、限流、统计、监控等通用功能需要在每个服务中单独实现,带来大量重复工作。
API 网关的作用就是把这些公共的功能抽取出来放到网关层实现,使得每个微服务只需要关心自身的业务逻辑。


API网关选型考虑

APISIX 作者温铭《API 网关的选型和持续集成》中提到的选型考虑:
1、路由配置
类似 nginx 中的 location 配置。考虑是否支持动态配置?是否支持四层路由和七层路由?路由表如何组织遍历,是list还是tree?

2、插件扩展
如何编写插件,什么语言?是否支持热加载?

3、存储
路由等配置如何存储?放关系数据库还是内存kv?(kong放postgres,apisix是放etcd)


API网关常用架构方案

基于 Nginx+Lua+ OpenResty 的方案,Kong,orange 都是基于这个方案
基于 Netty、非阻塞IO模型。 通过网上搜索可以看到国内的宜人贷等一些公司是基于这种方案,是一种成熟的方案。
基于 Node.js 的方案。 这种方案是应用了 Node.js 天生的非阻塞的特性。
基于 java Servlet 的方案。 zuul 基于的就是这种方案,这种方案的效率不高,这也是 zuul 总是被诟病的原因。


开源产品

kong

一、功能
1、实现:基于 OpenResty(ngnix+lua)
2、路由配置:支持动态api路由配置。定期5秒轮询加载。
3、存储:PostgreSQL 或 Cassandra
4、管理界面:Kong dashboard

二、性能
借助于 Nginx 的事件驱动模型和非阻塞 IO, 性能优异。
OpenResty 和 kong 性能相近,大概是直连的 60%~70%

三、扩展性
编写lua脚本扩展,但不支持热加载。

优势:
劣势:需要专门的运维人员去维护


zuul

一、功能
1、实现:基于 Java Servlet 实现,集成在 Spring Boot 微服务内。
2、路由配置:Spring Boot 配置文件形式,搭配配置中心(比如Archaius)可做动态配置。
3、存储:无单独存储,Spring Boot 配置文件或配置中心。
4、无自带控制台,需要搭配其他组件
5、限流:编写 filter 实现,单机或分布式。

二、性能:
zuul 1.x 采用阻塞 IO 和多线程方式,即一个线程处理一次连接请求,当出现问题时,如后端延迟或设备错误重试,活跃的连接和线程数量会增加,这会加大服务器负载并可能使集群无法承受,性能损失较大。
zuul 2.x 多路复用 IO reactor 模式(netty)。zuul 2.x 和 Spring Cloud Gateway 性能相近,大概为直连的 40%

三、扩展性
zuul: Java 代码编写的 filter 不支持热加载。groovy 编写的 filter 支持热加载(轮询)。

四、选型考虑
zuul 1.x 的优势是基于 Srping Cloud 生态,但从 2018.12 开始 Spring Cloud netflix 组件已进入维护模式,此部分优势丢失。且由于 zuul 1.x 严重的性能问题,不建议使用。

Spring Cloud 网关组件主推 Spring Cloud Gateway, 无 zuul 2.x 集成计划。

zuul 2.x 不断跳票,性能低于 Spring Cloud Gateway, Spring 微服务中无特殊需求不推荐使用 zuul 2.x.


Spring Cloud Gateway

一、功能
1、实现:基于 Spring 5.x + Spring Boot 2.x + Reactor 实现,响应式的、非阻塞式的 API

二、性能

三、扩展性

四、选型考虑


zuul工作流程

在 zuul 中, 整个请求的过程是这样的,首先将请求给 zuulservlet 处理,zuulservlet 中有一个 zuulRunner 对象,该对象中初始化了 RequestContext 作为存储整个请求的一些数据,并被所有的 zuulfilter 共享。zuulRunner 中还有 FilterProcessor, FilterProcessor 作为执行所有的 zuulfilter 的管理器。FilterProcessor 从 filterloader 中获取 zuulfilter, 而 zuulfilter 是被 filterFileManager 所加载,并支持 groovy 热加载,采用了轮询的方式热加载。有了这些 filter 之后,zuulservelet 首先执行的 Pre 类型的过滤器,再执行 route 类型的过滤器,最后执行的是 post 类型的过滤器,如果在执行这些过滤器有错误的时候则会执行 error 类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。


Spring Boot 中启用 Zuul

maven 添加依赖:

<dependencyManagement>
  <dependencies>
    <!-- 管理Spring Cloud生态各组件的版本 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>Finchley.SR3</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency<name />
  </dependencies>
</dependencyManagement>

<!-- Netflix Zuul 微服务网关 -->
<dependencies>
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
  </dependency>
</dependencies>

应用主类使用 @EnableZuulProxy 注解开启Zuul

@EnableZuulProxy
@SpringCloudApplication
public class Application {
    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }
}

EnableZuulProxy 源码如下

package org.springframework.cloud.netflix.zuul;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.context.annotation.Import;

@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {
}

路由转发

application.properties

zuul.routes.route-name.path: /backend/**
zuul.routes.route-name.url: http://localhost:${server.port}

或 application.yml

zuul:
  routes:
    route-name:
      path: /backend/**
      url: http://localhost:${server.port}

其中 route-name 是路由的名字,可以任意定义,每个路由规则由一个 path 和一个 url 组成, 匹配path的请求会被转发到 url

之后,所有 /backend/** 的请求都会自动转发到 http://localhost:${server.port}

过滤器

定义过滤器只需要继承 ZuulFilter 抽象类实现其定义的四个抽象函数就可对请求进行拦截与过滤。

filterType():返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:

  • PRE:该类型的filters在Request routing到源web-service之前执行。可以进行一些权限认证,日志记录,或者额外给Request增加一些属性供后续的filter使用;
  • ROUTING:该类型的filters用于把Request routing到源web-service,源web-service是实现业务逻辑的服务。这里使用HttpClient请求web-service; 一般用于构建发送给微服务的请求,并使用Apache HttpClient或Netflix Ribbon构建和发送原始HTTP请求的位置。
  • POST:该类型的filters在ROUTING返回Response后执行。用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端;
  • ERROR:上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理。

filterOrder():通过int值来定义过滤器的执行顺序

shouldFilter():返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。

run():过滤器的具体逻辑。需要注意,这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,当然我们也可以进一步优化我们的返回,比如,通过ctx.setResponseBody(body)对返回body内容进行编辑等。

服务网关Spring Cloud Zuul(Finchley版本)
https://www.jianshu.com/p/f5cdce29890d

跟我学Spring Cloud(Finchley版)-16-Zuul
http://www.itmuch.com/spring-cloud/finchley-16/

Spring Cloud构建微服务架构(五)服务网关(Brixton版,比较老旧)
http://blog.didispace.com/springcloud5/

Spring Cloud 4.8 Router and Filter: Zuul (路由配置讲的比较多)
https://my.oschina.net/roccn/blog/826655


上一篇 Raft分布式一致性算法

下一篇 SSO单点登录

阅读
评论
2k
阅读预计8分钟
创建日期 2019-05-21
修改日期 2021-07-28
类别

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论