深度剖析Gateway在微服务治理中的关键角色

目录

一、多层网关

二、Gateway 路由规则

        2.1 路由

        2.2 谓词

        2.3 过滤器

三、路由声明规则

        3.1 谓词

        寻址谓词

        请求参数谓词

        时间谓词

        自定义谓词


一、多层网关

        首先我们先了解下一个请求是如何到达服务端并得到相应的。过程如图所示:

        首先网址解析的第一步是 DNS 解析。当用户在浏览器输入网址后,这个网址会被 DNS 层解析成一个可被访问的 IP 地址。为了避免单点故障,可以在这一层加双保险,比如将域名映射成多个 IP 地址做主备,又或者根据用户 IP 所属区域做 Loadbanacer,将请求导向就近的 IP 地址。

        每一个 IP 地址只是所谓的虚 IP,后面会映射到一个大型的网关集群,这个集群便是我们业务系统外的第一道网关。在这个环节,使用最广泛而且最经济实惠技术选型就是 Nginx 反向代理。因为它拥有超强的并发能力,而且很节省内存资源。

        一个请求抵达最外层的 Nginx 服务之后,还可能会经历多级 LVS+Nginx 集群的转发。大公司之所以这么做,主要是出于对网络安全的考虑。他们往往会根据业务系统的属性和安全级别来设置不同的网络分区,而这些网络分区之间是相互独立的,分区之间需要开通白名单或者防火墙才能打通连接。比如有的网络分区可以直接对外,而有的高安全级别的分区(比如金融类业务)则部署在更底层。这就和我们使用跳板机访问线上机房是一个道理。

        然后,请求经过了多级网关服务的转发,抵达了最后的微服务层。在这一层上,Gateway 就需要出马来负责请求转发了。

        Gateway 既然叫“微服务网关”,就说明它自己就是一个微服务。换句话说,它也是 Nacos服务注册中心的一员。既然 Gateway 能连接到 Nacos,那么就意味着它可以轻松获取到 Nacos中所有服务的注册表。这样一来,Gateway 就可以根据本地的路由规则,将请求精准无误地送达到每个微服务组件中。

        使用 Gateway 有一个显而易见的好处,那就是高可扩展性。当你对后台的微服务集群做扩容或缩容的时候,Gateway 可以从 Nacos 注册中心轻松获取所有服务节点的变动,不需要任何额外的配置,一切都在无感知的情况下自然而然地发生。如果使用其他技术方案,你可能还需要花些力气修改节点列表,将新增的机器手动添加到列表中,还要把移除的机器从列表中删除。

二、Gateway 路由规则

        Gateway 的路由规则主要有三个部分,分别是路由、谓词和过滤器。如下图:

        

        2.1 路由

        路由是 Gateway 的一个基本单元,路由都有一个目标地址,这个目标地址就是当前路由规则要调用的目标服务。那么一条路由规则在什么情况下会调用目标服务呢?这就看路由的谓词设置了。

        2.2 谓词

        所谓谓词,实际上就是路由的判断规则,一个路由中可以添加多个谓词组合。如果一个服务请求满足某个路由里所有谓词规则,这时 Gateway 就会把请求转发到设置的目标地址。

        打个比方,你可以为某个路由设置一条谓词规则,约定访问路径的匹配规则为 Path=/user/*,在这种情况下只有以 /user 打头的请求才会被当前路由选中。

        Gateway 为我们提供了非常丰富的内置谓词,你可以通过内置谓词构建复杂的路由条件,甚至连“整点秒杀”这个场景都能在网关层做控制。

        2.3 过滤器

       过滤器和路由、目标地址之间是什么关系呢?其实 Gateway 在把请求转发给目标地址的过程中,把这个任务全权委托给了 Filter(过滤器)来处理。如下图:

        Gateway 组件使用了一种 FilterChain 的模式对请求进行处理,每一个服务请求(Request)在发送到目标服务之前都要被一串 FilterChain 处理。同理,在 Gateway 接收服务响应(Response)的过程中也会被 FilterChain 处理一把。

        Gateway 的过滤器主要分为两种,一种是 GlobalFilter,也就是“全局过滤器”;另一种是 GatewayFilter,也就是对指定路由生效的“局部过滤器”。

        Gateway 还有一系列用来做路径转发、请求跨域、WebSocket、WebClient 和 Loadbalancer 功能支持的全局过滤器。

三、路由声明规则

        路由是 Gateway 中的一条基本转发规则。网关在启动的时候,必须将这些路由规则加载到上下文中,才能正确处理服务转发请求。那么网关可以从哪些地方加载路由呢?

        Gateway 提供了三种方式来加载路由规则,分别是 Java 代码、ymal 文件和动态路由。

        第一种加载方式是 Java 代码声明路由,它是可读性和可维护性最好的方式,可以使用一种链式编程的 Builder 风格来构造一个 route 对象,比如在下面的例子里。它声明了两个路由,根据 path 的匹配规则将请求转发到不同的地址。

@Bean
public RouteLocator declare(RouteLocatorBuilder builder) {return builder.routes().route("id-001", route -> route.path("/user/**").uri("http://xxx.com")).route(route -> route.path("/test/**").uri("http://www.test.com")).build();
}

        第二种方式是通过配置文件来声明路由,你可以在 application.yml 文件中组装路由规则。我把前面定义的 Java 路由规则改写成了 yml 版,可以参考一下。

spring:cloud:gateway:httpclient:connect-timeout: 30000response-timeout: 30sroutes:- id: useruri: http://user.test.compredicates:- Path=/user/**filters:- name: HttpPostBodyEnhance- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 1000redis-rate-limiter.burstCapacity: 1000redis-rate-limiter.requestedTokens: 1key-resolver: '#{@uriKeyResolver}'metadata:response-timeout: 20000connect-timeout: 20000- id: producturi: http://product.test.compredicates:- Path=/product/**metadata:response-timeout: 120000connect-timeout: 120000

        不管是 Java 版还是 yml 版,它们都是通过“hardcode”的方式声明的静态路由规则,这些 Route 只会在项目启动后被加载一次。如果你想要在 Gateway 运行期更改路由逻辑,那么就要使用第三种方式:动态路由加载。

        动态路由也有不同的实现方式。如果你在项目中集成了 actuator 服务,那么就可以通过 Gateway 对外开放的 actuator 端点在运行期对路由规则做增删改查。但这种修改只是临时性的,项目重新启动后就会被打回原形,因为这些动态规则并没有持久化到任何地方。

        动态路由还有另一种实现方式,那就是借助 Nacos 配置中心来存储路由规则。Gateway 通过监听 Nacos Config 中的文件变动,就可以动态获取 Nacos 中配置的规则,并在本地生效了。我将在后面的课程中带你落地一套 Nacos+Gateway 的动态路由。

        3.1 谓词

        Gateway 的内置谓词很多,这里捡一些比较常用的谓词,为你介绍下它们的用法。我把这些谓词大致分为三个类型:寻址谓词、请求参数谓词和时间谓词。我将使用基于 Java 代码的声明方式,带你挨个来看下如何在路由中配置谓词。

        寻址谓词

        针对请求地址和类型做请求判断的谓词条件,比如这里用到的 path,其实就是一种路径匹配条件,当请求的 URL 和 path 谓词指定的模式相匹配时,这个谓词就会返回一个 TRUE 的判断,而 method 谓词则是根据请求的 http method 作为判断条件,比如这里就限定了只有 GET 和 POST 请求才能访问当前 Route。

.route("id-1", route -> route.path("/user/**").and().method(HttpMethod.GET, HttpMethod.POST).uri("http://user.test.com")

        在上面这段代码中,添加了不只一个谓词。在谓词与谓词之间,可以使用and、or、negate这类与或非逻辑连词进行组合,构造一个复杂判断条件。

        请求参数谓词

        这类谓词主要对请求所附带的参数进行判断。这里的参数不单单是 Query 参数,还可以是Cookie 和 Header 中包含的参数。如下代码,如果请求中包含指定参数,或者指定参数的值和指定的 regex 表达式不匹配,那么请求就无法满足当前路由的谓词判断。

.route("id-1", route -> route// 验证cookie.cookie("myCookie", "regex")// 验证header.and().header("myHeaderA").and().header("myHeaderB", "regex")// 验证param.and().query("paramA").and().query("paramB", "regex").and().remoteAddr("远程服务地址").and().host("pattern1", "pattern2")

        时间谓词

        可以借助before、after、between这三个时间谓词来控制当前路由的生效时间段。

.route("id-1", route -> route// 在指定时间之前.before(ZonedDateTime.parse("2024-04-25T14:33:47.789+08:00"))// 在指定时间之后.or().after(ZonedDateTime.parse("2024-04-25T14:33:47.789+08:00"))// 或者在某个时间段以内.or().between(ZonedDateTime.parse("起始时间"),ZonedDateTime.parse("结束时间"))

        自定义谓词

        如果内置谓词不满足要求,想要实现自定义谓词,可以通过 Gateway 的可扩展谓词工厂来实现自定义谓词,Gateway 组件提供了一个统一的抽象类 AbstractRoutePredicateFactory 作为谓词工厂,你可以通过继承这个类来添加新的谓词逻辑。

        

// 继承自通用扩展抽象类AbstractRoutePredicateFactory
public class MyPredicateFactory extends AbstractRoutePredicateFactory<MyPredicateFactory.Config> {public MyPredicateFactory() {super(Config.class);}// 定义当前谓词所需要用到的参数@Validatedpublic static class Config {private String myField;}@Overridepublic List<String> shortcutFieldOrder() {// 声明当前谓词参数的传入顺序// 参数名要和Config中的参数名称一致return Arrays.asList("myField");}// 实现谓词判断的核心方法// Gateway会将外部传入的参数封装为Config对象@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new GatewayPredicate() {// 在这个方法里编写自定义谓词逻辑@Overridepublic boolean test(ServerWebExchange exchange) {return true;}@Overridepublic String toString() {return String.format("myField: %s", config.myField);}};}
}

        

往期经典推荐

手把手教你实现服务高可用性-CSDN博客

决胜微服务架构:OpenFeign轻量级REST客户端的魅力解析_feign配置loadbalancer-CSDN博客

一文看懂Nacos如何实现高效、动态的配置中心管理_nacos 动态配置-CSDN博客

TiDB内核解密:揭秘其底层KV存储引擎如何玩转键值对_tidb 的key value是如何做到的-CSDN博客

深入剖析MongoDB集群架构设计_mongodb 集群-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/641475.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT客户端的开发框架

针对QT客户端开发&#xff0c;目前存在多种框架&#xff0c;各有优缺点&#xff0c;具体选择哪种框架取决于您的具体需求和项目特点。以下是一些流行的QT客户端开发框架。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1. Qt框架 Qt…

Golang | Leetcode Golang题解之第41题缺失的第一个正数

题目&#xff1a; 题解&#xff1a; func firstMissingPositive(nums []int) int {n : len(nums)for i : 0; i < n; i {for nums[i] > 0 && nums[i] < n && nums[nums[i]-1] ! nums[i] {nums[nums[i]-1], nums[i] nums[i], nums[nums[i]-1]}}for i …

element中file-upload组件的提示‘按delete键可删除’,怎么去掉?

问题描述 element中file-upload组件会出现这种提示‘按delete键可删除’ 解决方案&#xff1a; 这是因为使用file-upload组件时自带的提示会盖住上传的文件名&#xff0c;修改一下自带的样式即可 ::v-deep .el-upload-list__item.is-success.focusing .el-icon-close-tip {d…

C语言编译成bin文件关键过程

一、关键步骤 将单片机的源代码转换成二进制文件&#xff08;bin文件&#xff09;的过程涉及几个关键步骤&#xff0c;这些步骤是编译过程中的标准组成部分&#xff0c;主要包括以下步骤&#xff1a;预处理、编译、汇编、链接、二进制转换。 1、预处理 这是编译过程的第一步…

【Python-Spark(大规模数据)】

Python-Spark&#xff08;大规模数据&#xff09; ■ Spark■ PySparl编程模型■ 基础准备■ 数据输入■ RDD的map成员方法的使用■ RDD的flatMap成员方法的使用■ RDD的reduceByKey成员方法的使用■ 单词计数统计■ RDD的filter成员方法的使用■ RDD的distinct成员方法的使用■…

【每日力扣】41. 缺失的第一个正数 238. 除自身以外数组的乘积 189. 轮转数组

&#x1f525; 个人主页: 黑洞晓威 &#x1f600;你不必等到非常厉害&#xff0c;才敢开始&#xff0c;你需要开始&#xff0c;才会变的非常厉害 41. 缺失的第一个正数 给你一个未排序的整数数组 nums &#xff0c;请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为…

0.5W 3KVDC 隔离单、双输出 DC/DC 电源模块——TPV-W5 24V 48V 系列

TPV-W5系列提供正负双输出和单输出&#xff0c;工业级环境温度&#xff0c;用于PCB安装的国际标准结构。此系列产品小巧&#xff0c;效率高&#xff0c;低输出纹波及能承受3000V以上的耐压&#xff0c;用于需要正负电压或单输出和高隔离电压的场合。封装有SIP和DIP可选。

快刀斩乱麻,DevOps让代码评审也自动起来

​在 Dr.Michaela Greiler 的 How Code Reviews at Microsoft 一文中提到&#xff0c;微软有 140000 名员工&#xff0c;其中 44%员工是工程师。这意味着&#xff0c;有超过 6000 名的工程师同时在同一个代码库上开发 Office、Visual Studio、Windows 等产品。 想要确保不同子…

面试宝典(1)——数据库篇(MySQL)

面试宝典&#xff08;1&#xff09;——数据库篇&#xff08;MySQL&#xff09; 1.什么是索引&#xff1f; 索引是一种用于加快数据库查询速度的数据结构。 索引可以帮助数据库快速定位到数据库表中特定列的记录&#xff0c;从而加快数据检索和查询的速度。 通过在表的列上…

使用Azure AI Search和LlamaIndex构建高级RAG应用

RAG 是一种将公司信息合并到基于大型语言模型 &#xff08;LLM&#xff09; 的应用程序中的常用方法。借助 RAG&#xff0c;AI 应用程序可以近乎实时地访问最新信息&#xff0c;团队可以保持对其数据的控制。 在 RAG 中&#xff0c;您可以评估和修改各个阶段以改进结果&#x…

Web3钱包开发获取测试币-Base Sepolia(二)

Web3钱包开发获取测试币-Base Sepolia(二) ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b0c0ac86b04a496087471388532bc54a.png) 基于上篇 Web3钱包开发获取测试币-Polygon Mumbai(一) &#xff1a;https://suwu150.blog.csdn.net/article/details/137949473 我…

Git 仓库内容操作

Git 仓库内容操作 | CoderMast编程桅杆Git 仓库内容操作 添加文件到暂存区 使用如下指令将工作区的文件添加到暂存区&#xff0c;告诉 Git 在下次 commit 时哪些文件做出了修改。 commit 指令详看后续 添加一个或多个文件到暂存区&#xff1a; 添加指定目录到暂存区 添加当前目…