关于Zuul的几个问题
本文来说下关于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的几个问题相关推荐
- 【微服务架构】SpringCloud之路由网关(zuul)
什么是zuul zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用. Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架.Zu ...
- zuul两大作用_SpringCloud微服务(05):Zuul组件,实现路由网关控制
一.Zuul组件简介 1.基础概念 Zuul 网关主要提供动态路由,监控,弹性,安全管控等功能.在分布式的微服务系统中,系统被拆为了多个微服务模块,通过zuul网关对用户的请求进行路由,转发到具体的后 ...
- spring cloud微服务治理eureka、hystrix、zuul代码例子
spring cloud微服务中台服务代码例子,包括eureka.hystrix.zuul https://github.com/birdstudiocn/spring-cloud-sample/tr ...
- zuul 启动 threw exception_SpringCloud-Zuul-网关路由过滤器
标注: SpringBoot版本:<version>2.1.11.RELEASE</version> SpringCloud版本:<spring-cloud.versio ...
- java 类隔离_微服务架构中zuul的两种隔离机制实验
ZuulException REJECTED_SEMAPHORE_EXECUTION 是一个最近在性能测试中经常遇到的异常.查询资料发现是因为zuul默认每个路由直接用信号量做隔离,并且默认值是100 ...
- Spring Cloud入门教程 - Zuul实现API网关和请求过滤
简介 Zuul是Spring Cloud提供的api网关和过滤组件,它提供如下功能: 认证 过滤 压力测试 Canary测试 动态路由 服务迁移 负载均衡 安全 静态请求处理 动态流量管理 在本教程中 ...
- Spring Cloud(七)服务网关 Zuul Filter 使用
上一篇文章中,讲了Zuul 转发,动态路由,负载均衡,等等一些Zuul 的特性,这个一篇文章,讲Zuul Filter 使用,关于网关的作用,这里就不再次赘述了,重点是zuul的Filter ,我们可 ...
- Spring Cloud(六)服务网关 zuul 快速入门
服务网关是微服务架构中一个不可或缺的部分.通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由.均衡负载功能之外,它还具备了权限控制等功能.Spring Cloud Netflix中 ...
- springCloud Zuul网关
1.springboot 仅2.0.x 支持,在此选择 2.0.7 2.新建Module eureka-zuul-client 3.导入依赖 <?xml version="1.0&qu ...
- SpringCloud的服务网关zuul
演示如何使用api网关屏蔽各服务来源 一.概念和定义 1.zuul最终还是使用Ribbon的,顺便测试一下Hystrix断路保护 2.zuul也是一个EurekaClient,访问服务注册中心,获取元 ...
最新文章
- QEMU — VirtIO 虚拟化
- c++中函数模板的显示具体化
- PHP实用小程序(四)
- 著名开源项目_著名开源项目案例研究
- AMP (LAMP/WAMP)
- cocos2d-x 之TableView
- JS精粹知识点和我的解释
- Redis初识、设计思想与一些学习资源推荐
- 3dmax渲染完就卡住不动,怎么办
- idea使用svn拉取项目代码_idea下载svn的项目并且运行操作
- Android listview局部刷新
- 黑莓7290中文系统下载_无法将Blackberry 7290升级到最新的系统软件
- Paragon ntfs2022轻松让mac读写NTFS格式磁盘移动硬盘U盘
- 去重插入数据 mysql_mysql 数据去重
- java发送lrc文件格式_java中用正則表達式解析LRC文件
- 爬虫:信息提取的一般方法
- 成都拓嘉启远:拼多多评论置顶该怎样去弄
- 故事版xib --view上添加tableview
- 坚持学英语 -- 公司前台MM 一日英语小记
- servlet3.1规范翻译:第13章 安全
热门文章
- 修改Tomcat Connector运行模式,优化Tomcat运行性能
- MySQL里的日期技巧
- Meteor——以NodeJS为基础环境,MongoDB为数据环境的全栈开发平台!
- cocos2d-x物业现场
- 深入理解 Android Activity的生命周期
- Spring启动异常: cvc-elt.1: Cannot find the declaration of element 'beans'(转)
- 浪擎全融合灾备云获大数据安全领域最佳创新奖
- Vue2.0+ElementUI+PageHelper实现的表格分页
- 学习dubbo遇到的问题1
- 【186天】黑马程序员27天视频学习笔记【Day15-上】