微服务:微服务的应用可能部署在不同机房,不同地区,不同域名下。
例如银行、证券等领域常见的前置机系统,它也是解决访问认证、 报文转换、访问统计等问题的。Spring Cloud GateWay提供如下一些功能:
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0构建
- 解决跨域请求问题(jf-驾驶舱项目)
- 熔断:集成 Hystrix 断路器
- 集成 Spring Cloud DiscoveryClient
- Predicates 和 Filters 作用于特定路由,易于编写的 Predicates 和 Filters
- 基于 Filter 链的方式,提供了一些网关的高级功能:
- 性能: API 高可用,负载均衡,容错机制。
- 路由:提供统一的动态路由/API 路由管理方式,能够匹配任何请求属性;
- 限流:流量控制,错峰流控,可以定义多种限流规则。
- 路径重写
- 安全性:权限身份认证、脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制)。
- 监控/指标:记录请求响应数据,API 耗时分析,性能监控。
- 日志:日志记录,一旦涉及分布式,全链路跟踪必不可少。
- 缓存:数据缓存。
- 灰度:线上灰度部署,可以减小风险。
常用网关解决方案:
- Nginx + Lua
- kong
- Traefik
- Spring Cloud Netflix Zuul
- Spring Cloud Gateway
-
API 网关是一个单独、独立运行的服务器,是一个中间件。有多种实现方式:
-
redis
-
zool
-
spring cloud gateway
-
-
网关就是所有项目的一个统一入口:
单体应用:浏览器发起请求到单体应用所在的机器,应用从数据库查询数据原路返回给浏览器,对于单体应用来说是不需要网关的。
微服务:微服务的应用可能部署在不同机房,不同地区,不同域名下。此时客户端(浏览器/手机/软件工具)想要请求对应的服务,都需要知道机器的具体 IP 或者域名 URL,当微服务实例众多时,这是非常难以记忆的,对于客户端来说也太复杂难以维护。此时就有了网关,所有外部请求率先经过微服务网关,客户端只需要与网关交 互(只需要知道网关地址即可),然后由网关根据请求标识解析判断出具体的微服务地址,再把请求转发到微服务实例。这其中的记忆功能就全部交由网关来操作了。 - 目标是替代 Zuul。
Springcloud中所集成的Zuul版本,采用的是Tomcat容器,使用的是传统的Servlet IO处理模型。是基于过滤器的,是阻塞 IO,不支持长连接。如下图所示: 大家知道,servlet由servlet container进行生命周期管理。container启动时构造servlet对象并调用servlet init()进行初始化;container关闭时调用servlet destory()销毁servlet;container运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用service()。
弊端:servlet是一个简单的网络IO模型,当请求进入servlet container时,servlet container就会为其绑定一个线程,在并发不高的场景下这种模型是适用的,但是一旦并发上升,线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。在一些简单的业务场景下,不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势。
所以Springcloud Zuul 是基于servlet之上的一个阻塞式处理模型,即spring实现了处理所有request请求的一个servlet(DispatcherServlet),并由该servlet阻塞式处理处理。所以Springcloud Zuul无法摆脱servlet模型的弊端。虽然Zuul 2.0开始,使用了Netty,并且已经有了大规模Zuul 2.0集群部署的成熟案例,但是,Springcloud官方已经没有集成改版本的计划了。 - 目标提高性能。
为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的reactor-netty响应式编程组件,此底层使用了Netty通讯框架。从特征来说,SpringCloud Gateway和Zuul的特征差别不大。SpringCloud Gateway和Zuul最主要的区别,还是在底层的通信框架上。 Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。官方结构图: Webflux虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Netty,毕竟,Netty是目前业界认可的最高性能的通信框架。而Webflux的Loop线程,正好就是著名的Reactor 模式IO处理模型的Reactor线程,如果使用的是高性能的通信框架Netty,这就是Netty的EventLoop线程 - 高可用网关【图灵】【乐字节】:
为了保证 Gateway 的高可用性,可以同时启动多个 Gateway 实例进行负载,在 Gateway 的上游使用 Nginx 或者 F5 进行负载转发以达到高可用。
网关 = 路由转发 + 过滤器(编写额外功能)
简单说明一下三个术语:
- Filter(过滤器):
- 过滤器将会对请求和响应进行处理。
- 在Gateway运行过程中Filter负责在代理服务“之前”或“之后”去做一些事情。
- 所有生效的Filter都是GatewayFilter的实例
- Route(路由):
- 接收外界请求,通过网关的路由转发,转发到后端的服务上。
- 一个Route模块由一个 ID,一个目标 URI,一组断言和一组过滤器定义组成。
- ID是自定的
-
URI就是一个地址
-
Predicate过滤器
-
Filter过滤器
- 如果断言为真,则说明请求的 URI 和配置匹配,目标URI会被访问。
- 注意1:Zuul的路由配置模块类似。
- 注意2:只讨论路由功能的话,它和nginx反向代理服务器很像(外界访问nginx,由nginx做负载均衡,后把请求转发到对应服务器上)。
- Predicate(断言、谓词)
- 简单点理解谓词就是一些附加条件和内容,可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。
- 断言的输入类型是一个 ServerWebExchange。
- 第一步:客户端向 Spring Cloud Gateway 发出请求。
- 第二步:请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文
- 第三步:Gateway中Handler Mapping映射中找到与请求相匹配的路由。
- 第四步:将路由发送到网关 Web 处理程序 Gateway Web Handler。
- 第五步:Gateway Web Handler 会被Filter进行过滤。
- 第六步:Gateway 基于 Filter 链的方式提供了网关基本的功能,Filter中前半部分代码是处理请求的代码。
- 第七步:处理完成后调用真实被代理的服务,被代理服务响应结果。
- 第八步:结果会被Filter中后半部分代码进行操作。
- 第九步:原路返回:
- 操作完成后把结果返回给Gateway Web Hanlder,
- 在返回给Gateway Handler Mapping,
- 最终响应给客户端。
- 下载nginx:学习时,一般使用windows版的nginx
- 安装nginx:解压文件后直接运行根路径下的 nginx.exe 文件即可。
- 测试nginx:Nginx 默认端口为 80,访问:http://localhost:80/ 看到下图说明安装成功。
- 配置路由规则:
进入 Nginx 的 conf 目录,打开 nginx.conf 文件,配置路由规则: - 测试
访问:http://localhost/api-product/product/1 结果如下:
访问:http://localhost/api-order/order/1 结果如下:
动态路由其实就是面向服务的路由,Spring Cloud Gateway 支持与 Eureka 整合开发,根据 serviceId 自动从注册中心获取服务地址并转发请求,这样做的好处不仅可以通过单个端点来访问应用的所有服务,而且在添加或移除服务实例时不用修改 Gateway 的路由配置。
- 第一步:Eureka Server:Gateway依赖Eureka,需要从Eureka中获取真实代理项目地址后,在进行访问。
- 第二步:新建普通的Eureka Client项目DemoOne(项目名:demo-one)
- 第三步:新建项目GatewayDemo(项目名:gateway-demo)
- 第四步:新建配置文
server:
port: 9000
spring:
application:
name: gateway-demo
cloud:
gateway:
discovery:
locator:
enabled: true # 开启当前项目服务注册与发现功能
lower-case-service-id: true # 把服务名转换为小写,Eureka中默认都是大写
routes:
- id: demo #自定义唯一标识,只要不重复即可
uri: lb://EUREKA-CLIENT # lb:loadBalance EUREKA-CLIENT 代理项目的名
predicates: Path=/demo/** # 路径规则
filters: StripPrefix=1 # 转发后忽略第一层 - 第五步:访问测试:http://localhost:9000/demo/one
通过结果可以看出,用户虽然访问的GatewayDemo网关项目,但是最后真是访问的是DemoOne项目中/one 控制器
- 方式一:基础URI路由配置方式
如果请求的目标地址,是单个的URI资源路径,配置文件示例如下 - 方式二:基于代码的路由配置方式
转发功能同样可以通过代码来实现,我们可以在启动类 GateWayApplication 中添加方法 customRouteLocator() 来定制转发规则。 - 方式三:和注册中心相结合的路由配置方式
在uri的schema协议部分为自定义的lb:类型,表示从微服务注册中心(如Eureka)订阅服务,并且进行服务的路由。
注册中心相结合的路由配置方式,与单个URI的路由配置,区别其实很小,仅仅在于URI的schema协议不同。单个URI的地址的schema协议,一般为http或者https协议
1)Predicates谓词:当满足条件在进行路由转发。
- 其中Route和Predicate必须同时申明
- 所有的谓词都设置在predicates属性中,
- 当设置多个谓词时取逻辑与条件,
- 且一个谓词只能设置一组条件,如果需要有个多条件,添加多个相同谓词。
- 案例:Path=/demo/** 实际上使用的就是PathRoutePredicateFactory
- 网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现:
- 假设 转发uri都设定为http://localhost:9023
2)过滤器规则(Filter)
-
Filter作用:在路由转发到代理服务之前和代理服务返回结果之后额外做的事情。
-
Filter执行了说明谓词条件通过了。
-
Spring Cloud Gateway中Filter分类:
-
内置Filter,都是GatewayFilter实现类
-
自定义GlobalFilter
-
-
GlobalFilter【sxt】:全局过滤器不需要工厂,也不需要配置,直接对所有的路由都生效。
-
自定义FilterFactory【sxt】:可以定义针对于Router的Filter。
- 类名必须叫做XXXGatewayFilterFactory.注入到Spring容器后使用时的名称就叫做XXX。
- 类必须继承AbstractGatewayFilterFactory
- 所有需要传递进来的参数都配置到当前类的内部类Config中
请求超时、异常。请求失败堆积于网关。需要快速失败并返回给客户端。不然系统崩溃。
2 解决方案:熔断降级- Spring Cloud Gateway 可以利用Hystrix实现服务降级等功能。
- 当Gateway进行路由转发时,如果发现下游服务连接超时或产生异常,此时就允许进行服务降级。
- 实现原理:当连接超时时,使用Gateway自己的一个降级接口返回托底数据,保证程序继续运行
顾名思义,限流就是限制流量,就像你宽带包有 1 个 G 的流量,用完了就没了。通过限流,我们可以很好地控制系统的 QPS,从而达到保护系统的目的。
比如 Web 服务、对外 API,这种类型的服务有以下几种可能导致机器被拖垮:
1.用户增长过快(好事) 2.因为某个热点事件(微博热搜) 3.竞争对象爬虫 4.恶意的请求 这些情况都是无法预知的,不知道什么时候会有 10 倍甚至 20 倍的流量打进来,如果真碰上这种情况,扩容是根本来不及的。 从上图可以看出,对内而言:上游的 A 、 B 服务直接依赖了下游的基础服务 C ,对于 A , B 服务都依赖的基础服务 C 这种场景,服务 A 和 B 其实处于某种竞争关系,如果服务 A 的并发阈值设置过大,当流量高峰期来临,有可能直接拖垮基础服务 C 并影响服务 B ,即雪崩效应。 2 解决方案:可以利用Gateway中RequestRateLimiter实现限流。(1)常见的限流算法
- 计数器算法
- 漏桶算法
- 令牌桶算法
(2)Gateway中限流,RequestRateLimiter是基于Redis和Lua脚本实现的令牌桶算法。
七 功能【网】④:健康检查配置:admin-client、actuator
八 功能【网】⑤:统一配置跨域请求【网】【图灵】【乐字节】
现在的请求通过经过gateWay网关时,需要在网关统一配置跨域请求,需求:所有请求通过,有如下配置:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "*"
allowed-headers: "*"
allow-credentials: true
allowed-methods:
- GET
- POST
- DELETE
- PUT
- OPTION
九 具体【网】①:整合Nacos 十 具体【网】②:整合Swagger聚合微服务系统API文档 十一 具体【网】③:整合Sentinel完成流控和降级 十二 参考
SpringCloud gateway (史上最全) - 疯狂创客圈 - 博客园
全网最全讲解 Spring Cloud Gateway,认真看完这一篇就够了!
一篇就看懂:SpringCloud网关 - GateWay详解
SpringCloud Gateway获取body参数(一篇就够了)
Spring Cloud Gateway解决跨域问题【理解跨域】



