首先微服务是为了构建复杂系统而生的,如果并发所有系统都适合使用微服务架构,任何技术都是为了解决具体应用业务场景而生的,离开了业务场景谈技术都是耍流氓!可能你会说,我们做基础开发不做业务,基础开发面向的领域跟业务领域可能不同而已,即领域模型不同而已,其实都是使用编码解决不各自领域的问题,就好像是网络七层模型,大家处于不同层次而已。
使用微服务网关之前可以思考如下几个问题:
1、为什么要用微服务网关,如果不用行不行?
2、我们不用微服务是否也可以用微服务网关?
相信大家对Nginx并不陌生,微服务网关能做什么,简单说跟Nginx一样都能反向代理,也就是说可以做前后端分离。还有吗?当然。当你的项目还是初期的时候,你可能只需要用到做前后分离即可。当你应用庞大之后你需要对系统进行拆解,你可能会有商品服务、购物车服务、商品详情、支付服务、物流服务等等,而且你可能会有PC端、APP端、小程序等等,当业务部门精心准备一场购物盛宴的时候,你可能还会遇到洪水般的流量,你如何保障系统平稳运行,如丝般顺滑。不是说一个就能解决所有问题,而且以上这些问题网关都能起到至关重要的作用。看到这里上面问题的相信大家心里已有答案。
微服务网关:
zuul1.0 : netflix 公司开源的,基于 Serlvet ,与Spring Cloud 集成。优点:开发容易、编程模型简单。缺点:连接数限制、线程上下切换开销、延迟阻塞耗尽线程连接资源.适用于CPU密集型,例如计算视频编解码,图像处理,加解密,压缩解压等等
zuul2.0: 基于Netty实现异步非阻塞编程模型.优点:线程开销少、连接数易扩展 缺点:编程模型复杂,调试复杂 适用于IO密集型如,web服务器
kong: nginx+lua
SpringCloud Gateway: 基于Spring Boot 2.x, Spring WebFlux
......
市面的网关还有很多我们就不一一列举了,根据我的经验入门难度来排序:
zuul1.0<zuul2.0<SpringCloud Gateway<kong
今天我们先来看一下SpringCloud Gateway
SpringCloud Gateway 通过匹配路由规则然后执行相应动作。
一、引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
二、路由转发规则
路由转发规则定义说明:
id: 路由规则唯一识别
predicates: 谓词工厂,触发转发条件:After Before Between Cookie Header Host Method Path Query RemoteAddr Weight
uri:转发地址
filter: 路由过滤器允许以某种方式修改传入HTTP请求或输出HTTP响应。路由筛选器的作用域是特定路由。SpringCloudGateway包括许多内置的GatewayFilter工厂:
AddRequestHeader AddRequestParameter AddResponseHeader DedupeResponseHeader Hystrix PrefixPath PreserveHostHeader RequestRateLimiter Redis RateLimiter RedirectTo
order: 路由规则优先级
application.yaml
spring:
cloud:
gateway:
routes:
SpringCloudGateway 路由配置规则很丰富,我们针对我们常用的场景进行举例:
根据路径(Path)匹配转发实现前后分离
假设我们的前端是NodeJs项目,我们通过ajax分别访问商品服务、订单服务。
- 静态文件服务器:proxy.static.url
- 商品后台API服务器:proxy.api.goods.url
- 订单后台API服务器:proxy.api.order.url
PS: 假设所有静态资源访问根路径 /,商品服务访问/api/goods/** ,订单服务访问/api/order/**
针对这种场景我们进行如下配置即可实现:
spring:
cloud:
gateway:
routes:
- id: static
predicates:
- Path=/**
uri: ${proxy.static.url} #静态资源服务器,如 html,js,css,img等
order: 1000
- id: api_goods
predicates:
- Path=/api/goods
uri: ${proxy.api.goods.url} #商品 API 服务器
order: 1000
- id: api_order
predicates:
- Path=/api/order
uri: ${proxy.api.order.url} #订单 API 服务器
order: 1000
根据路径(Path)识别应用,并重定向到 / 。适用于遗留系统接入网关(遗留系统大多使用根路径:/)。 RewritePath 支持正则表达式,分组提取
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://example.org #后端应用服务
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo(?<segment>/?.*), $\{segment}
根据主机(Host)识别应用 适用于遗留系统接入网关但又想保留原始域名等,此种方式接入网关改造量最少也能保留原始域名是目前最优方案。
PS: 需要将应用原始域名CNAME到网关域名
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org #后端应用服务
predicates:
- Host=**.somehost.org,**.anotherhost.org
网关跨域配置,支持复杂请求,如POST SSE websocket 等
由网关代为跨域,后端应用可以不做跨域处理
spring:
cloud:
gateway:
routes:
- id: spider_route
uri: ws:${proxy.api.url}
predicates:
- Path=/**
filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin # 如果后端服务器也进行跨域支持,需要加上此项。作用是进行返回头去重
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*" #生产环境为了安全考虑请配置具体域名
allowedMethods:
- POST
- GET
- DELETE
- PUT
allowedHeaders: "*" #不配置此项可支持简单请求跨域如:GET、DELETE 如要兼容复杂请求如:POST SSE 请求此项必不可少