SpringCloud第十章,升级篇,服务网关GateWay、服务配置Config和服务总线Bus
一、服务网关GateWay
1、网关概述
为什么存在:
不同的微服务一般会有不同的网络地址,而外部的客户端可能需要调用多个微服务的接口才能完成一个业务的需求,如果让客
户端和多个微服务直接通信,会产生很多问题:
a、客户端多次请求不同的微服务,增加客户端的复杂性
b、存在跨域请求,在一定场景下处理困难
c、认证复杂,每个微服务都需要独立的认证
d、难以重构,随着项目的迭代,可能需要重新划分微服务。
例如:可能会将多个微服务合并成一个或者将一个微服务拆分成多个微服务。这是如果客户端直接与各微服务间通信,增加重构的难度。
e、某些微服务可能使用了防火墙或者浏览器的不友好协议,直接访问会有一定的困难。
什么是服务网关:
网关是介于客户端和服务端之间的中间层。所有的外部请求都会经过网关这一层。也就是说API实现方面更多的考虑业务逻辑。而安全、性能、监控可以交友网关来做。这样既提高了业务的灵活性又不失安全性。
有什么优点:
a、安全,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
b、易于监控,可以在网关收集监控数据推送到外部系统进行监控。
c、易与认证,可以在网关上进行认证,然后再将请求转发到后端的微服务,无需再每个微服务上进行认证。
d、减少了客户端和各微服务之间的交互次数。
e、易于统一鉴权。验证用户是否具有访问各微服务的权利。
2、什么是GateWay
是什么:
一句话:gateway是zuul1.x版的替代。
springcloud gateway旨在为微服务架构提供一种简单有效的统一的API路由管理方式。并且基于filter链的方式提供网关的基本功能:安全、监控、熔断、限流、重试等。
能干什么
反向代理、鉴权、流量控制、熔断、日志监控等
gateway和zuul1.x的区别:
zuul1.x是基于servlet之上的一个阻塞式处理模型。
gateway是非阻塞式的。
3、核心概念
a、断言predicate:
参考java8的predicate,开发人员可以匹配http请求中的所有内容。如果请求和路由相匹配则进行路由。
b、过滤Filter:
指的是spring框架中springGateway的实例,可以对请求在路由前或之后进行修改。
c、路由Route:
路由是构建网关的基本模块,它由ID、目标URI、一系列断言predicate和过滤器filter组成。如果断言为true则匹配该路由。
web请求通过一些匹配条件,定位到真正的服务节点,并在这个转发的过程前后进行一系列的精细化控制。
predicate就是我们的匹配条件,而filter,就可以理解为一个无所不能的拦截器,有了这两个元素再加上一个uri就可以实现一个具体的路由了。
4、gateway工作流程
客户端向springcloud gateway发出请求,然后在gateway handler mapping中找到与请求相匹配的路由,将其发送到gateway web handler.
handler再通过指定的过滤器链来将请求发送到实际服务执行业务逻辑,然后返回。
过滤器可能会在发送请求之前pre或者之后post执行业务逻辑。
pre:参数校验、权限校验、流量监控、日志输出、协议转换等。
post:相应内容和响应头的修改,日志输出、流量监控等。
5、案例
5.1、生产者前增加9527网关
新建module : cloud-gateway-9527
<parent>
<artifactId>cloud_2020</artifactId>
<groupId>com.lee.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway-9527</artifactId>
POM:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud_2020</artifactId>
<groupId>com.lee.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway-9527</artifactId>
<dependencies>
<!--新增gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.lee.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
主启动类:
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GateWayMain9527.class,args);
}
}
测试:
1、启动eureka7001、provider-8001、gateway-9527
2、访问:http://localhost:8001/payment/get/1
3、访问:http://localhost:9527/payment/get/1
结果都是:
{"code":200,"message":"查询数据成功 serverPort:8001Payment(id=1, serial=001)","data":null}
实现了在8001服务前增加了一个9527。
5.2、优化
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
目前我们的配置是http://localhost:8001基于微服务具体地址的。但是payment-provider的微服务在实际生产环境下可能会有多个服务。所以我们要基于provider在注册中心中的微服务名称来进行动态路由。
默认情况下:gateway会根据注册中心的服务列表,以注册中心上的微服务名称创建动态路由进行转发,从而实现动态路由的功能。
修改cloud-gateway-9527 application.yml
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
##uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #lb表示启用gateway的负载均衡功能 在eureka中根据微服务名称找到URI
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2
##uri: http://localhost:8001
uri: lb://cloud-payment-service #lb表示启用gateway的负载均衡功能 在eureka中根据微服务名称找到URI
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
测试:
1、启动eureka-7001、provider-8001、provider-8002、gateway-9527
2、访问:http://localhost:9527/payment/get/1
结果返回:
{"code":200,"message":"查询数据成功 serverPort:8001Payment(id=1, serial=001)","data":null}
或者
{"code":200,"message":"查询数据成功 serverPort:8002Payment(id=1, serial=001)","data":null}
8001和8002端口微服务轮询使用,证明我们访问9527通过微服务名称可以调用对应的微服务
5.3、Predicate使用
我们在启动cloud-gateway-9527的时候,后台加载了如下:
Springcloud gateway内置了许多route predicate工厂,这些prediacate都与http请求的不同属性相匹配。多个
route predicate可以进行组合使用。
springcloud gateway创建route对象,RoutePredicateFactory创建predicate对象,predicate对象赋值给route。
常见的route predicate:
1、After Route Predicate
例:- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
2、Before Route Predicate
例:- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
3、Between Route Predicate
例:- Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai] , 2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
4、Cookie Route Predicate
例:- Cookie=username,lee #并且Cookie是username=lee才能访问
5、Header Route Predicate
例:- Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
6、Host