本文来说下关于Zuul的几个问题

文章目录

  • 概述
  • 微服务网关
  • Zuul简单实现
    • 依赖导入
    • 主启动类注解
    • application.yml 配置文件
    • 测试一下
  • 自定义路由规则
  • Zuul 的路由功能
    • 简单配置
    • 统一前缀
    • 路由策略配置
    • 服务名屏蔽
    • 路径屏蔽
    • 敏感请求头屏蔽
  • Zuul 的过滤功能
    • 简单实现一个请求时间日志打印
    • 令牌桶限流
    • 关于 Zuul 的其他
  • 本文小结

概述

Zuul 是由 Netflix 孵化的一个致力于“网关 “解决方案的开源组件。Zuul 是从设备和 web 站点到 Netflix 流应用后端的所有请求的前门。作为边界服务应用,Zuul 是为了实现动态路由、监视、弹性和安全性而构建的。它还具有根据情况将请求路由到多个 Amazon Auto Scaling Groups(亚马逊自动缩放组,亚马逊的一种云计算方式) 的能力。

Zuul 包含了对请求的路由和过滤两个最主要的功能。其中,路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。而过滤功能则是负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。

Zuul 和 eureka 进行整合,将 zuul 自身注册为 eureka 服务治理下的应用,同时从 eureka 中获得其他微服务的消息,也即以后的访问微服务都是通过 zuul 跳转之后获得。

所以,Zuul 提供:代理+路由+过滤三大功能。接下来,我们来看一看如何实现


微服务网关

我们学习了 Eureka 之后我们知道了 服务提供者 是 消费者 通过 Eureka Server 进行访问的,即 Eureka Server 是 服务提供者 的统一入口。那么整个应用中存在那么多 消费者 需要用户进行调用,这个时候用户该怎样访问这些 消费者工程 呢?当然可以像之前那样直接访问这些工程。但这种方式没有统一的消费者工程调用入口,不便于访问与管理,而 Zuul 就是这样的一个对于 消费者 的统一入口。

大家对网关应该很熟吧,简单来讲网关是系统唯一对外的入口,介于客户端与服务器端之间,用于对请求进行鉴权、限流、 路由、监控等功能。


没错,网关有的功能,Zuul 基本都有。而 Zuul 中最关键的就是 路由和过滤器 了,在官方文档中 Zuul 的标题就是。

Router and Filter : Zuul


Zuul简单实现

依赖导入

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

我们需要将 zuul 注册到 eureka,所以也需要导入 eureka client 依赖


主启动类注解

在主启动类中需要添加:@EnableZuulProxy 注解,表示开启 zuul 代理。

@SpringBootApplication
@EnableZuulProxy
public class ZuulGateway {public static void main(String[] args) {SpringApplication.run(ZuulGateway.class, args);}
}

application.yml 配置文件

接下来看看 application.yml 配置文件,由于要注册到 eureka,所以和 eureka 相关的配置,也是需要的,如下

# 服务端口号
server:port: 6001spring:application:name: microservice-zuul-gateway # 对外暴露的服务名称# 客户端注册进eureka服务列表里
eureka:client:service-url:defaultZone: http://eureka01:7001/eureka/,http://eureka02:7002/eureka/,http://eureka03:7003/eureka/,healthcheck:enabled: trueinstance:instance-id: zuul网关服务-6001  # 人性化显示出服务的信息prefer-ip-address: true    # 访问路径可显示ip地址lease-renewal-interval-in-seconds: 2lease-expiration-duration-in-seconds: 5# 使用actuator来展示项目的基本信息
info:author.name: liuqi wuapp.name: microserviceserver.port: ${server.port}application.name: ${spring.application.name}

测试一下

启动 eureka 集群、订单服务(8001)和 zuul-gateway(6001)。在浏览器中输入 http://eureka7001:7001 ,可以看到如下信息,说明服务都正常注册到 eureka。

我们首先直接访问一下订单服务,确保服务可用:http://localhost:8001/provider/order/get/1。

然后我们通过 zuu l来访问该订单服务:http://localhost:6001/microservice-order/provider/order/get/1 ,也可以正常访问。microservice-order 是订单服务的服务名。即 zuul 在 eureka 里找到了一个叫 microservice-order 的订单服务,然后去请求数据。所以说,zuul 是可以根据注册到 eureka 中的服务名称来访问服务的。

那么我们自然会想到,如果我把三个订单服务都启动起来,因为它们的服务名称都是 microservice-order,zuul 到底会将请求转发给哪个服务呢?

启动下 8001、8002 和 8003,然后还是访问http://localhost:6001/microservice-order/provider/order/get/1 ,查看输出的信息,可以知道,zuul 中默认集成了轮询的规则,三个服务轮流调用。


自定义路由规则

如果我们不想像上面那样在 url 中直接暴露微服务名称,可以在配置文件中配一下路由规则。

# 配置路由规则
zuul:routes:order:serviceId: microservice-orderpath: /order/**

这样的话,在配置了路由规则之后,就可以使用:http://localhost:6001/order/provider/order/get/1 来访问订单服务了。

但是这样的话,原来使用微服务名称的方式还是可以访问,所以我们可以禁用原来使用微服务名称的方式访问。如下:

# 配置路由规则
zuul:ignored-services: microservice-order # 不允许用微服务名访问了,如果禁用所有的,可以使用 "*"routes:# 如下指定新的映射order:serviceId: microservice-orderpath: /order/**

我们还可以给路由加一个统一的前缀

# 配置路由规则
zuul:ignored-services: microservice-order # 不允许用微服务名访问了,如果禁用所有的,可以使用 "*"routes:prefix: /zuul # 给路由加一个统一的前缀# 如下指定新的映射order:serviceId: microservice-orderpath: /order/**

这样的话,就可以使用:http://localhost:6001/zuul/order/provider/order/get/1 来访问订单服务了。


Zuul 的路由功能

简单配置

本来想复制一些代码,但是想了想,因为各个代码配置比较零散,看起来也比较零散,我决定还是给你们画个图来解释吧。比如这个时候我们已经向 Eureka Server 注册了两个 Consumer 、三个 Provicer ,这个时候我们再加个 Zuul 网关应该变成这样子了。


信息量有点大,我来解释一下。关于前面的知识我就不解释了。首先,Zuul 需要向 Eureka 进行注册,注册有啥好处呢?你傻呀,Consumer 都向 Eureka Server 进行注册了,我网关是不是只要注册就能拿到所有 Consumer 的信息了?拿到信息有什么好处呢?我拿到信息我是不是可以获取所有的 Consumer 的元数据(名称,ip,端口)

拿到这些元数据有什么好处呢?拿到了我们是不是直接可以做路由映射?比如原来用户调用 Consumer1 的接口 localhost:8001/studentInfo/update 这个请求,我们是不是可以这样进行调用了呢?localhost:9000/consumer1/studentInfo/update 呢?你这样是不是恍然大悟了?

这里的url为了让更多人看懂所以没有使用 restful 风格。上面的你理解了,那么就能理解关于 Zuul 最基本的配置了,看下面。

server:port: 9000
eureka:client:service-url:# 这里只要注册 Eureka 就行了defaultZone: http://localhost:9997/eureka

然后在启动类上加入 @EnableZuulProxy 注解就行了。没错,就是那么简单


统一前缀

这个很简单,就是我们可以在前面加一个统一的前缀,比如我们刚刚调用的是 localhost:9000/consumer1/studentInfo/update,这个时候我们在 yaml 配置文件中添加如下。

zuul:prefix: /zuul

这样我们就需要通过 localhost:9000/zuul/consumer1/studentInfo/update 来进行访问了。


路由策略配置

你会发现前面的访问方式(直接使用服务名),需要将微服务名称暴露给用户,会存在安全性问题。所以,可以自定义路径来替代微服务名称,即自定义路由策略。

zuul:routes:consumer1: /FrancisQ1/**consumer2: /FrancisQ2/**

这个时候你就可以使用 localhost:9000/zuul/FrancisQ1/studentInfo/update` 进行访问了。


服务名屏蔽

这个时候你别以为你好了,你可以试试,在你配置完路由策略之后使用微服务名称还是可以访问的,这个时候你需要将服务名屏蔽。

zuul:ignore-services: "*"

路径屏蔽

Zuul 还可以指定屏蔽掉的路径 URI,即只要用户请求中包含指定的 URI 路径,那么该请求将无法访问到指定的服务。通过该方式可以限制用户的权限。

zuul:ignore-patterns: **/auto/**

这样关于 auto 的请求我们就可以过滤掉了。

** 代表匹配多级任意路径*代表匹配一级任意路径

敏感请求头屏蔽

默认情况下,像 Cookie、Set-Cookie 等敏感请求头信息会被 zuul 屏蔽掉,我们可以将这些默认屏蔽去掉,当然,也可以添加要屏蔽的请求头。


Zuul 的过滤功能

如果说,路由功能是 Zuul 的基操的话,那么过滤器就是 Zuul的利器了。毕竟所有请求都经过网关(Zuul),那么我们可以进行各种过滤,这样我们就能实现 限流,灰度发布,权限控制 等等。


简单实现一个请求时间日志打印

要实现自己定义的 Filter 我们只需要继承 ZuulFilter 然后将这个过滤器类以 @Component 注解加入 Spring 容器中就行了。在给你们看代码之前我先给你们解释一下关于过滤器的一些注意点。


过滤器类型:Pre、Routing、Post。前置Pre就是在请求之前进行过滤,Routing路由过滤器就是我们上面所讲的路由策略,而Post后置过滤器就是在 Response 之前进行过滤的过滤器。你可以观察上图结合着理解,并且下面我会给出相应的注释

// 加入Spring容器
@Component
public class PreRequestFilter extends ZuulFilter {// 返回过滤器类型 这里是前置过滤器@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}// 指定过滤顺序 越小越先执行,这里第一个执行// 当然不是只真正第一个 在Zuul内置中有其他过滤器会先执行// 那是写死的 比如 SERVLET_DETECTION_FILTER_ORDER = -3@Overridepublic int filterOrder() {return 0;}// 什么时候该进行过滤// 这里我们可以进行一些判断,这样我们就可以过滤掉一些不符合规定的请求等等@Overridepublic boolean shouldFilter() {return true;}// 如果过滤器允许通过则怎么进行处理@Overridepublic Object run() throws ZuulException {// 这里我设置了全局的RequestContext并记录了请求开始时间RequestContext ctx = RequestContext.getCurrentContext();ctx.set("startTime", System.currentTimeMillis());return null;}
}
// lombok的日志
@Slf4j
// 加入 Spring 容器
@Component
public class AccessLogFilter extends ZuulFilter {// 指定该过滤器的过滤类型// 此时是后置过滤器@Overridepublic String filterType() {return FilterConstants.POST_TYPE;}// SEND_RESPONSE_FILTER_ORDER 是最后一个过滤器// 我们此过滤器在它之前执行@Overridepublic int filterOrder() {return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {return true;}// 过滤时执行的策略@Overridepublic Object run() throws ZuulException {RequestContext context = RequestContext.getCurrentContext();HttpServletRequest request = context.getRequest();// 从RequestContext获取原先的开始时间 并通过它计算整个时间间隔Long startTime = (Long) context.get("startTime");// 这里我可以获取HttpServletRequest来获取URI并且打印出来String uri = request.getRequestURI();long duration = System.currentTimeMillis() - startTime;log.info("uri: " + uri + ", duration: " + duration / 100 + "ms");return null;}
}

上面就简单实现了请求时间日志打印功能,你有没有感受到 Zuul 过滤功能的强大了呢?没有?好的、那我们再来


令牌桶限流

当然不仅仅是令牌桶限流方式,Zuul 只要是限流的活它都能干,这里我只是简单举个例子


我先来解释一下什么是 令牌桶限流 吧。首先我们会有个桶,如果里面没有满那么就会以一定 固定的速率 会往里面放令牌,一个请求过来首先要从桶中获取令牌,如果没有获取到,那么这个请求就拒绝,如果获取到那么就放行。很简单吧,啊哈哈。下面我们就通过 Zuul 的前置过滤器来实现一下令牌桶限流。

package com.lgq.zuul.filter;import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;@Component
@Slf4j
public class RouteFilter extends ZuulFilter {// 定义一个令牌桶,每秒产生2个令牌,即每秒最多处理2个请求private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}@Overridepublic int filterOrder() {return -5;}@Overridepublic Object run() throws ZuulException {log.info("放行");return null;}@Overridepublic boolean shouldFilter() {RequestContext context = RequestContext.getCurrentContext();if(!RATE_LIMITER.tryAcquire()) {log.warn("访问量超载");// 指定当前请求未通过过滤context.setSendZuulResponse(false);// 向客户端返回响应码429,请求数量过多context.setResponseStatusCode(429);return false;}return true;}
}

这样我们就能将请求数量控制在一秒两个,有没有觉得很酷


关于 Zuul 的其他

Zuul 的过滤器的功能肯定不止上面我所实现的两种,它还可以实现 权限校验,包括我上面提到的 灰度发布 等等。

当然,Zuul 作为网关肯定也存在 单点问题 ,如果我们要保证 Zuul 的高可用,我们就需要进行 Zuul 的集群配置,这个时候可以借助额外的一些负载均衡器比如 Nginx 。


本文小结

本文详细介绍了Zuul相关的知识与内容。

关于Zuul的几个问题相关推荐

  1. 【微服务架构】SpringCloud之路由网关(zuul)

    什么是zuul zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用. Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架.Zu ...

  2. zuul两大作用_SpringCloud微服务(05):Zuul组件,实现路由网关控制

    一.Zuul组件简介 1.基础概念 Zuul 网关主要提供动态路由,监控,弹性,安全管控等功能.在分布式的微服务系统中,系统被拆为了多个微服务模块,通过zuul网关对用户的请求进行路由,转发到具体的后 ...

  3. spring cloud微服务治理eureka、hystrix、zuul代码例子

    spring cloud微服务中台服务代码例子,包括eureka.hystrix.zuul https://github.com/birdstudiocn/spring-cloud-sample/tr ...

  4. zuul 启动 threw exception_SpringCloud-Zuul-网关路由过滤器

    标注: SpringBoot版本:<version>2.1.11.RELEASE</version> SpringCloud版本:<spring-cloud.versio ...

  5. java 类隔离_微服务架构中zuul的两种隔离机制实验

    ZuulException REJECTED_SEMAPHORE_EXECUTION 是一个最近在性能测试中经常遇到的异常.查询资料发现是因为zuul默认每个路由直接用信号量做隔离,并且默认值是100 ...

  6. Spring Cloud入门教程 - Zuul实现API网关和请求过滤

    简介 Zuul是Spring Cloud提供的api网关和过滤组件,它提供如下功能: 认证 过滤 压力测试 Canary测试 动态路由 服务迁移 负载均衡 安全 静态请求处理 动态流量管理 在本教程中 ...

  7. Spring Cloud(七)服务网关 Zuul Filter 使用

    上一篇文章中,讲了Zuul 转发,动态路由,负载均衡,等等一些Zuul 的特性,这个一篇文章,讲Zuul Filter 使用,关于网关的作用,这里就不再次赘述了,重点是zuul的Filter ,我们可 ...

  8. Spring Cloud(六)服务网关 zuul 快速入门

    服务网关是微服务架构中一个不可或缺的部分.通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由.均衡负载功能之外,它还具备了权限控制等功能.Spring Cloud Netflix中 ...

  9. springCloud Zuul网关

    1.springboot 仅2.0.x 支持,在此选择 2.0.7 2.新建Module eureka-zuul-client 3.导入依赖 <?xml version="1.0&qu ...

  10. SpringCloud的服务网关zuul

    演示如何使用api网关屏蔽各服务来源 一.概念和定义 1.zuul最终还是使用Ribbon的,顺便测试一下Hystrix断路保护 2.zuul也是一个EurekaClient,访问服务注册中心,获取元 ...

最新文章

  1. QEMU — VirtIO 虚拟化
  2. c++中函数模板的显示具体化
  3. PHP实用小程序(四)
  4. 著名开源项目_著名开源项目案例研究
  5. AMP (LAMP/WAMP)
  6. cocos2d-x 之TableView
  7. JS精粹知识点和我的解释
  8. Redis初识、设计思想与一些学习资源推荐
  9. 3dmax渲染完就卡住不动,怎么办
  10. idea使用svn拉取项目代码_idea下载svn的项目并且运行操作
  11. Android listview局部刷新
  12. 黑莓7290中文系统下载_无法将Blackberry 7290升级到最新的系统软件
  13. Paragon ntfs2022轻松让mac读写NTFS格式磁盘移动硬盘U盘
  14. 去重插入数据 mysql_mysql 数据去重
  15. java发送lrc文件格式_java中用正則表達式解析LRC文件
  16. 爬虫:信息提取的一般方法
  17. 成都拓嘉启远:拼多多评论置顶该怎样去弄
  18. 故事版xib --view上添加tableview
  19. 坚持学英语 -- 公司前台MM 一日英语小记
  20. servlet3.1规范翻译:第13章 安全

热门文章

  1. 修改Tomcat Connector运行模式,优化Tomcat运行性能
  2. MySQL里的日期技巧
  3. Meteor——以NodeJS为基础环境,MongoDB为数据环境的全栈开发平台!
  4. cocos2d-x物业现场
  5. 深入理解 Android Activity的生命周期
  6. Spring启动异常: cvc-elt.1: Cannot find the declaration of element 'beans'(转)
  7. 浪擎全融合灾备云获大数据安全领域最佳创新奖
  8. Vue2.0+ElementUI+PageHelper实现的表格分页
  9. 学习dubbo遇到的问题1
  10. 【186天】黑马程序员27天视频学习笔记【Day15-上】