Gateway一文详解
本文内容均来自SpringCloud官网
Gateway核心概念
路由(Route): 路由是网关的基本组成部分,路由信息由ID、目标URL、一组断言和一组过滤器组成,如果断言为真,则说明请求的URL和配置匹配。
断言(Predicate): Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者自定义匹配来自于Http Request中的任何信息,比如请求头和参数等
过滤器(Flute): 一个标准的SpringWebFilter,Spring Cloud Gateway中的Filter分为两种类型,分别是Gateway Filter和Globa lFilter,过滤器将会对请求和响应进行处理。
Gateway工作原理
下面的图表提供了关于SpringCloud网关如何工作的高级概述
客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。此处理程序通过特定于请求的过滤器链运行请求。过滤器被虚线分隔的原因是过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“pre”筛选逻辑。然后发出代理请求。发出代理请求后,运行“post”筛选逻辑
Gateway入门案例
前提准备:
注册中心:nacos或者eureka
两个业务服:任意web服务即可
网关服:gateway
关于服务注册发现还有业务服我这里就不搭建了。核心关注Gateway的环境搭建
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency></dependencies>
关于路由配置application.yml
spring:cloud:gateway:routes:- id: test_routeuri: https://www.baidu.compredicates: #断言如果请求路径中符合下面规则那么将请求交给uri中的服务处理- Query=url,baidu- id: auth #中央授权服uri: lb://yy-authpredicates:- Path=/auth/**- id: user #APP端用户服务uri: lb://yy-userpredicates:- Path=/user/**- id: admin #管理后台服务uri: lb://yy-adminpredicates:- Path=/admin/**- id: test #测试服uri: lb://yy-testpredicates:- Path=/test/**
以上配置就是gateway的基本路由配置下面会详细讲解各种路由配置规则!
Gateway路由规则
Spring Cloud Gateway创建Router对象时,使用Router对象时,使用RouterPredicateFactory创建Predicate对象可以赋值给Router
- Spring Cloud Gateway包含许多内置的Router Predicate Factories。
- 所有这些断言都匹配HTTP请求的不同属性
- 多个Router Predicate Factories可以通过逻辑与(and)结合起来一起使用
路由断言工厂RouterPredicateFactory包含的主要实现类如图所示,包括Datetime,请求远程地址、路由权重、请求头、Host地址、请求方法、请求路径和请求参数等类型的路由断言。
Path
spring:cloud:gateway:routes:- id: path_routeuri: https://example.orgpredicates:- Path=/red/{segment},/blue/{segment}
如果请求路径为,则其路径匹配,例如:/red/1 or /red/1/ or /red/blue or /blue/green
Query
不指定值
spring:cloud:gateway:routes:- id: query_routeuri: https://example.orgpredicates:- Query=green
如果请求包含green则匹配
指定值写法
spring:cloud:gateway:routes:- id: query_routeuri: https://example.orgpredicates:- Query=red, gree.
如果请求包含一个red查询参数,其值与gree匹配,则前面的路由将匹配。regexp,所以green和greet是匹配的
Method
spring:cloud:gateway:routes:- id: method_routeuri: https://example.orgpredicates:- Method=GET,POST
如果请求方法是GET或POST,则此路由匹配。
After
spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:- After=2020-02-02T20:20:20.000+08:00[Asia/shanghai]
此路由符合2020年2月2日20:20:20时间(亚洲/上海)后的任何请求。
RemoteAddr
spring:cloud:gateway:routes:- id: remoteaddr_routeuri: https://example.orgpredicates:- RemoteAddr=192.168.1.1/24
如果请求的远程地址是192.168.1.10,则此路由匹配。
Header
spring:cloud:gateway:routes:- id: header_routeuri: https://example.orgpredicates:- Header=X-Request-Id, \d+
如果请求有一个名为X-Request-Id的头,它的值与\d+正则表达式匹配(也就是说,它的值是一个或多个数字),则此路由匹配。
以上路由的匹配规则我这里就只搬运这么多,如有其它的规则请查看Gateway的官网
Gateway动态路由
什么是动态路由,其实也就是相对于上面配置中农url的值直接写的是固定的请求地址,这在实际微服务架构中是无法满足的,那么就需要整合服务注册/发现中心,nacos或者eureka都行!在url上不写固定的请求地址了,改成为服务注册的名字!这也就是所谓的动态路由罢了
spring:cloud:gateway:routes:- id: auth #中央授权服uri: lb://yy-authpredicates:- Path=/auth/**- id: user #APP端用户服务uri: lb://yy-userpredicates:- Path=/user/**- id: admin #管理后台服务uri: lb://yy-adminpredicates:- Path=/admin/**- id: test #测试服uri: lb://yy-testpredicates:- Path=/test/**
在正在的微服务开发过程中,可能有成千上百的微服务,如果都这样配置起来,那可太费劲了,那么Gateway还提供服务名称转发的配置规则!
Gateway服务名称转发
spring:cloud:gateway:discovery:locator:# 是否与服务发现组件进行结合,通过serviceId转发到具体服务实例enabled: true #是否开启基于服务发现的路由规则lower-case-service-id: true #是否将服务名称转换小写
那么这里请求的路径格式为http://gateway的id:prot/服务注册名称/访问路径,我那管理后台的微服务访问测试
http://localhost:5000/yy-admin/login
过滤器
Spring Cloud Gateway根据范围划分为Gateway Filter和Global Filter,二者区别如下:
- Gateway Filter:网关过滤器需要通过spring.cloud.routes.filters配置在具体路由下,只做用在当前路由或者通过spring.cloud.default-filters 配置在全局,作用在所有路由上。
- Global Filter:全局过滤器,不需要在配置文件中配置,作用在所有路由上,最终通过GatewayFilterAdapter 包装成GatewayFilterChain 可识别的过滤器,它为请求业务以及路由的URL转换为真实业务请求的地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。
网关过滤器用于拦截并链式处理Web请求,可以实现横切面与应用无关的需求,比如安全,超时访问的设置等。修改传入的HTTP请求或者传出的HTTP响应。Spring
Cloud Gateway
包含许多内置的网关过滤器工厂一共22个,包括头部过滤器,路径类过滤器,Hystrix过滤器和重写请求URL的过滤器,还有参数和状态码其他的过滤器,根据过滤器工程的用途来划分,可以分为以下几种:Header、Parameter、Path、Body、Status、Session、Redirect、Retry、RateLimiter和Hystrix
Path路径过滤器
路径过滤器可以实现URL重写,通过重写URL可以实现隐藏实际路径提高安全性,易于用户记忆和输入,易于被搜索引擎收录等优点,实现方式如下!
RewritePathGatewayFilterFactory-重写path过滤器
:
RewritePath网关过滤器工厂采用路径正则表达式参数和替换参数,使用Java正则表达式来灵活重写请求路径
spring:cloud:gateway:routes:- id: adminuri: lb://yy-adminpredicates:- Path=/admin/**filters:- RewritePath=/admin(?<segment>.*), /$\{segment}对于/admin/**的请求路径,这将在发出下游请求之前设置/**的路径。注意,由于YAML规范,应该用$\替换$。那么当我们请求为
admin/login是,通过这个过滤器后那么实际请求为/login
PrefixPathGatewayFilterFactory-前缀Path过滤器
:
PrefixPath网关过滤器工厂为匹配的URL添加指定的前缀
spring:cloud:gateway:routes:- id: adminuri: lb://yy-adminfilters:- PrefixPath=/mypath
StripPrefixGatewayFilterFactory-请求分割过滤器
:
StripPrefix网关过滤器工厂采用一个参数StripPrefix,该参数表示在将请求发送到下游之前从请求中剥离的路径个数
spring:cloud:gateway:routes:- id: adminuri: lb://yy-adminpredicates:- Path=/**filters:- StripPrefix=2如果请求路径为/api/123/admin/1那么通过StripPrefix过滤器后实际到达下游请求为/admin/1,这里的2是通过/进行拆分
SetPathGatewayFilterFactory
:
SetPath网关过滤器工厂采用路径模板参数。它提供了一种通过允许模板话路径段来操作请求的简单方法,使用了SpringFramework中的URL模板,允许多个匹配段。
spring:cloud:gateway:routes:- id: adminuri: lb://yy-adminpredicates:- Path=/api/admin/{segment}filters:- SetPath=/admin/{segment}
匹配对应的URL的请求,将匹配到的请求追加在目标URL之后,将/api/admin/111重写为/admin/111
Parameter参数过滤器
AddRequestParameter
网关过滤器工厂会将指定参数添加至匹配到的下游请求中。
spring:cloud:gateway:routes:- id: adminuri: lb://yy-adminpredicates:- Path=/admin/**filters:- RewritePath=/admin(?<segment>.*), /$\{segment}- AddRequestParameter=flag,1对于/admin/**的请求路径,这将在发出下游请求之前设置/**的路径。注意,由于YAML规范,应该用$\替换$。那么当我们请求为
admin/login是,通过这个过滤器后那么实际请求为/login,然后将/login参数上添加flag,并且值为1,注意这里是可以组合使用的!
Status状态过滤器
SetStatus
网关过滤器工厂采用单个状态参数,他必须是有效的Spring HttpStatus。它可以是整数404或者枚举NOT_FOUND的字符串表示。
spring:cloud:gateway:routes:- id: adminuri: lb://yy-adminpredicates:- Path=/admin/**filters:- SetStatus=404对于/admin/**的请求路径,同一返回状态码为404
全局过滤器GlobalFilter
全局过滤器不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它是请求业务以及路由的URL转换为真实业务服务请求地址的核心过滤器,不需要系统化时加载,并作用在每个路由上。
自定义过滤器
即使Spring Cloud Gateway自带许多实用的GatewayFilter Factory、Gateway
Filter、Global Filter、但是很多场景下我们任然希望可以自定义自己的过滤器,实现以下骚操作!
自定义网关过滤器需要实现两个接口:GatewayFilter、Ordered
@Component
public class CustomGatewayFilter implements GatewayFilter, Ordered {/***过滤器业务逻辑*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("自定义网关过滤器被执行");return chain.filter(exchange);//继续往下执行}/***过滤器执行顺序,值约小,优先级越高*/@Overridepublic int getOrder() {return 0;}
}
/**
* @description: 网关路由配置类
* @author TAO
* @date 2021/4/21 0:37
*/
@Configuration
public class GatewayRoutesConfiguration {@Beanpublic RouteLocator routeLocator(RouteLocatorBuilder builder){return builder.routes().route(r ->r//断言 ()判断条件.path("/admin/**")//目标URL,路由到微服务的地址.uri("lb://yy-admin")//注册自定义网关过滤器.filter(new CustomGatewayFilter())//路由唯一id.id("admin")).build();}
}
自定义全局过滤器
自定义全局过滤器实现指定接口,GlobalFilter、Ordered ,然后添加@Component即可,无需手动绑定
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {/***过滤器业务逻辑*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("自定义网关过滤器被执行");return chain.filter(exchange);//继续往下执行}/***过滤器执行顺序,值约小,优先级越高*/@Overridepublic int getOrder() {return 0;}}
使用全局过滤器实现鉴权
网关限流
顾名思义,限流就是限制流量,也就是限制服务器的QPS,就像你流量包只有1个G流量,用完就没了,通过限流,我们可以很好的控制系统的QPS,从而达到保护系统的目的。
为什么需要限流
比如web服务、对外暴露的API这种类型的服务有一下几种可能导致机器被拖垮
- 用户增长过快
- 应某个热点事件()微博热搜
- 竞争对象爬虫
- 恶意请求
这些情况都是无法预知的,不知道设么时候会用10倍设置20倍的流量打进来,如果真碰上这种情况,扩容时根本来不及的
从上图可以看出,对内而言:上游A、B服务直接依赖下游基础服务C对于A、B服务都依赖C这种场景服务A、B其实存于某种竞争关系,如果A服务并发阈值设置过大,当流量高峰期来临时,有可能直接拖垮基础服务C并影响B服务,即服务雪崩效应!
限流算法
常见限流算法有:
- 计数器算法
- 漏铜算法
- 令牌桶算法
计数器算法
计数器双发是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,我们1分钟访问次数不能超过100个那么我们可以这么做:在一开始的时候,我们可以设置一个计时器counter,当每一个请求过来的时候,counter就加1,如果counter的值大于100且该请求的时间间隔还在1分钟之内,触发限流;如果该请求于第一个请求大于1分钟,重置counter从新计数,具体算法的示意图如下;
这个算法虽然简单,但是存在一个十分致命的问题,那就是灵界问题,如下图!
从上图中我们可以看出,假设有一个恶意用户,他在0:59时,瞬间发送100个请求,并且1:00又发送100个请求,那么这个用户在1秒的时间里面,瞬间发送了200个请求,我们刚才规定的是1分钟最多100个请求,也就是每秒最多1.7个请求,用户通过在时间窗口的重要节点出突发请求,可以瞬间超过我们的速率限制,用户有可能通过算法的这个漏洞,瞬间压垮我们的服务器!然而这并不是计数器算法唯一的漏洞,还有另外一个问题,就是极大的造成服务器资源浪费,如下图!
我们的预期想法是希望100个请求可以均匀的分布在这1分钟内,假设30S以内我们就请求上线了,那么剩余半分钟服务器就处于闲置状态!
漏铜算法
漏铜算法其实也很简单,可以初略的认为就是注水漏水的过程,往桶中任意速率流入水,以一定速率流出水,当水超过桶流量则丢弃,因为桶的容量是不变的,保证了整体的速率!
漏桶算法是使用队列机制实现的!
当然咯,漏桶算法也是存在问题的,假设我们桶的容量是100,然后我们流出为1秒一个,那么当我们瞬间请求100,那么就会造成请求堆积,会让网关压力过大,甚至导致网关服务崩溃,我们网关背后的微服务,请求处理能力只要每秒大于1,那么都会造成微服务的资源浪费,漏桶算法就是牺牲自己,保护别人,就是把压力都集中在网关自己身上,这种限流算法也是不完美的!
令牌桶算法
令牌桶算法是对漏铜算法的一种改进,漏铜算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用,在令牌桶算法中,存在一个桶,用来存放固定数量的令牌,算法中存在一种机制,以一定的速率往桶中放令牌,每次请求调用需要先获取令牌,只管拿到令牌,才有机会继续执行,否则选择等待可用的令牌,或者直接拒绝,放令牌的这个动作是持续不断的进行,如果桶中令牌达到上限,就丢弃令牌
场景大致是这样的:桶中一直有大量可用的令牌,这是进来请求可以直接拿到令牌执行,比如QPS为100/S,那么限流器初始化完成1秒后,桶中就已经有了100个令牌了,等服务启动完成对外提供服务时,该限流器可以抵挡瞬间的100个请求,当桶中没有令牌时,请求会进行等待,最后相当于一定的速率执行
Spring Cloud Gateway内部就是使用该算法,大概描述如下:
- 所有的请求在处理之前都需要拿到一个可用的令牌才会被处理
- 根据限流大小,设置按照一定的速率往桶里添加令牌
- 桶设置最大的放置令牌限制,当桶满时,新添加的令牌就丢弃或者拒绝
- 请求到达后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他业务逻辑,处理完业务逻辑之后,将令牌直接删除;
- 令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完后将不会删除令牌,以此保证足够的限流
漏桶算法主要的用途在于保护它人,而令牌桶算法主要的目的在于保护自己,将请求压力交于目标服务处理,假设突然进来很多请求,只要拿到令牌这些请求会瞬时被处理调用目标服务。
Gateway一文详解相关推荐
- Kong API Gateway 管理API详解
Kong API Gateway 管理API详解 2018-09-25 / Linuxops 版权说明:本文为博主原创,如果转载请注明来源.作为学习笔记,不能保证所有知识点是完全正确以及表达无误,用 ...
- 一文详解JavaBean 看这篇就够了
一文详解JavaBean 看这篇就够了 JavaBean的历史渊源 JavaBean的定义(通俗版) JavaBean应用 < jsp:useBean > < jsp:getProp ...
- 【卷积神经网络结构专题】一文详解AlexNet(附代码实现)
关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! [导读]本文是卷积神经网络结构系列专题第二篇文章,前面我们已经介绍了第一个真正意义 ...
- 一文详解 YOLO 2 与 YOLO 9000 目标检测系统
一文详解 YOLO 2 与 YOLO 9000 目标检测系统 from 雷锋网 雷锋网 AI 科技评论按:YOLO 是 Joseph Redmon 和 Ali Farhadi 等人于 2015 年提出 ...
- 一文详解决策树算法模型
AI有道 一个有情怀的公众号 上文我们主要介绍了Adaptive Boosting.AdaBoost演算法通过调整每笔资料的权重,得到不同的hypotheses,然后将不同的hypothesis乘以不 ...
- 「软件项目管理」一文详解软件配置管理计划
一文详解软件配置管理计划 前言 一.配置管理概述 1. 配置管理(SCM)定义 2. 软件配置项目(SCI) 3. 基线 4. 软件配置控制委员会(SCCB) 二.软件配置管理过程 1. 管理过程 2 ...
- 「软件项目管理」一文详解软件项目质量计划
一文详解软件项目质量计划
- 「软件项目管理」一文详解软件项目管理概述
一文详解软件项目管理概述
- OpenCV-Python实战(12)——一文详解AR增强现实
OpenCV-Python实战(12)--一文详解AR增强现实 0. 前言 1. 增强现实简介 2. 基于无标记的增强现实 2.1 特征检测 2.2 特征匹配 2.3 利用特征匹配和单应性计算以查找对 ...
- Python-Matplotlib可视化(10)——一文详解3D统计图的绘制
Python-Matplotlib可视化(10)--一文详解3D统计图的绘制 前言 3D散点图 3D曲线图 3D标量场 绘制3D曲面 在3D坐标轴中绘制2D图形 3D柱形图 系列链接 前言 Matpl ...
最新文章
- CentOS 7.2修改网卡名称
- android DecorView的使用
- Mysql表分区的选择与实践小结
- 大话“用户注册激活,忘记密码”发送邮件功能
- 蓝桥杯JAVA省赛2013-----B------4(黄金连分数)
- 人人都能看懂的机器学习!3个案例详解聚类、回归、分类算法
- 并行编程走下神坛 将成为开发者基本技能?
- python使用-Python3 错误和异常
- HDU 5978 2016ICPC大连 H: To begin or not to begin
- html木马制作教程,利用Internet Explorer Object Data漏洞制做全新网页木马
- 苹果开发者账号申请及升级更换
- 【Python】windows下Eclipse中安装集成webpy框架
- Android高德地图自定义地图指南针
- 让siri变语音计算机,iOS12新功能将释放Siri潜力 让它变身真正语音助手
- 大蒜敷脚心涌泉穴的功效和具体方法
- MATLAB 处理大数据
- 用python提取不同的两列数据对比_比较两列数据fram中的值
- 穷举法:一道爱因斯坦的数学题
- idea字体颜色修改
- 不一样的精巧:高级机械原理——全动画图解
热门文章
- 8.系统研发中的领导意志
- Android中的占位符
- 学术捜索新添找寻新近文章功能
- linux 查看nas磁盘阵列,NAS(linux)阵列管理
- vue + ElementUI + BMap 百度地图实现地图选址定位并获取地址信息
- Cent OS (一)Cents OS的基本安装
- Darkside勒索病毒的网络防御措施
- 解决ios微信公众号h5页面新增底部前进后退导航栏产生的布局问题
- IOS微信分享调起微信后立刻返回到app中无法分享的问题
- lol最克制诺手的英雄_LOL:最克制诺手的三个英雄,剑姬上榜,第一能打得诺手出不了塔...