微服务为什么需要API网关
, 因为在微服务架构中,后端服务往往不直接开放给客户端
,而是通过一个API网关
根据请求的url,
路由
到相应的服务。当添加API网关后,在第三方客户端和后端服务之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,而后将请求均衡分发给后台服务端。Spring Cloud提供了解决方案: zuul网关
.
API网关
为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式
,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。它实现了请求路由、负载均衡、校验过滤、服务容错、服务聚合等功能
。
Zuul
路由是微服务架构的不可或缺的一部分,提供动态路由,监控,弹性,安全等的边缘服务。
Zuul
是Netflix出品的一个基于JVM路由和服务端的负载均衡器(微服务网关
)。
主要功能有代理
, 动态路由
, 过滤器
等.
Zuul的GitHub开源→
官网资料→
Zuul
可以和Eureka, Ribbon, Hystrix等组件配合使用. 使用Eureka服务注册和发现的网关微服务架构图:
路由, 过滤, 负载均衡, 灰度发布等.
灰度发布, 又称金丝雀发布.
起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如
果金丝雀不叫了,就代表瓦斯浓度高。
在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进
行线上测试,启动的这个新版本应用,就是我们的金丝雀。如果没有问题,那么可以将少量的用户流
量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做
各种数据对比,就是所谓的A/B测试。新版本没什么问题,那么逐步扩大范围、流量,把所有用户都迁
移到新版本上面来。
路由
功能负责将外部请求转发到具体的服务实例上去,是实现统一访问入口的基础.
创建网关微服务[microservicecloud-zuul-gateway]
导入zuul
和eureka客户端
的依赖(网关服务本身也需要注册到Eureka)
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-zuulartifactId>
dependency>
启动类添加@EnableZuulProxy
注解, 开启网关代理配置.
/**
* zuul 网关启动类
*/
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy // 开启Zuul的代理配置
public class ZuulGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulGatewayApplication.class, args);
}
}
application.yml文件中添加注册到eureka的配置.
server:
port: 10010
spring:
application:
name: zuul-gateway
## Eureka客户端配置
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://www.eureka01.com:7001/eureka,http://www.eureka02.com:7002/eureka,http://www.eureka03.com:7003/eureka
instance:
prefer-ip-address: true
instance-id: zuul-gateway-01
application.yml文件中配置路由规则, 路由规则的配置方式有好几种. 下面分别列出.
## zuul路由配置
## 路由映射配置方式1, 也是默认的配置
zuul:
routes:
microservicecloud-provider:
path: /microservicecloud-provider
serviceId: microservicecloud-provider
microservicecloud-consumer:
path: /microservicecloud-consumer
serviceId: microservicecloud-consumer
提示
:
转发的路径path
和路由的微服务实例名称serviceId
一致时, 完全可以省略zuul的动态路由配置. 也就是上面的是默认配置.
只有在配置文件中出现的映射规则会被创建路由,而从Eureka中获取的其他服务,zuul将不会为它们创建路由规则。
启动网关微服务后, 我们不再直接访问后端服务
了, 而是通过网关微服务
进行路由转发. 下面是默认路由配置的测试结果.
默认的路由配置规则在实际应用场景中, 也是存在问题的. 后端微服务的实例名称暴露在url中, 可能存在安全隐患. 下面通过自定义path的方式, 在请求的url中使用别名
, 再由Zuul网关
进行路由转发到后端具体的服务提供方
.
## 路由映射配置方式2, 隐藏微服务名称,使用别名路径
zuul:
routes:
myprovider:
path: /myprovider/**
serviceId: microservicecloud-provider
myconsumer:
path: /myconsumer/**
serviceId: microservicecloud-consumer
或者简化写法
## 路由映射配置方式2, 隐藏微服务名称,使用别名路径
zuul:
routes:
myprovider.path: /myprovider/**
myprovider.serviceId: microservicecloud-provider
myconsumer.path: /myconsumer/**
myconsumer.serviceId: microservicecloud-consumer
路由映射配置使用自定义path后, 原来默认的路由映射规则也是生效的, 仍然可以通过上面的方式请求. 为了不暴露后端服务实例名称, 我们使用自定义path的url请求, 下面是测试结果.
使用更简洁的zuul.routes.
配置方式 , 使用方式和测试效果与上面一样.
zuul.routes.microservicecloud-provider=/myprovider/**
zuul.routes.microservicecloud-consumer=/consumer/**
## 路由映射配置方式3, 简化版
zuul:
routes:
microservicecloud-provider: /myprovider/**
microservicecloud-consumer: /consumer/**
API网关
在使用中, 也可以通过配置项过滤掉不想使用网关路由规则的微服务实例或path. 例如某些时候,
有一些服务我们不需要对外开放也被外部访问到了。这个时候我们可以使用zuul.ignore-services
参数来设置一个服务名匹配表达式来定义不自动创建路由的规则
。zuul在自动创建服务路由的时候会根据该表达式来进行判断,如果服务名匹配表达式,那么zuul将跳过该服务,不为其创建路由规则。
比如,设置为zuul.ignored-services='*'
,zuul将对所有的服务都不自动创建路由规则.
配置忽略服务
zuul:
# 此处省略部分路由配置...
ignored-services: microservicecloud-api # 忽略的微服务实例; '*' 表示忽略所有的微服务路由
ignored-patterns: /**/hello/** # 忽略的path
上面配置了为microservicecloud-api
忽略(不创建路由规则), 过滤掉了该服务实例的路由.
那么 http://localhost:port/microservicecloud-api/**/**
的url请求将不会被路由转发, 请求不通.
还可以给在请求网关的ur
l中添加前缀
支持.
zuul:
# 此处省略部分路由配置...
prefix: /gatewayto # 网关访问的前缀
由于Zuul自动集成了Ribbon和Hystrix
,所以Zuul天生就有负载均衡和服务容错能力
.
检查不可以少的端点访问依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
添加端点暴露, 提交端点访问的配置
# 开启查看路由的端点
management:
endpoints:
web:
exposure:
include: 'routes'
重启zuul网关微服务, 访问 http://localhost:10010/actuator/routes
, 可以查看路由信息.
动态路由功能在真正运行时,它的路由映射
和请求转发
都是由几个不同的Zuul过滤器完成的。
路由映射
由pre类型
的过滤器完成,它将请求路径与配置的路由规则进行匹配,以找到需要转发的目标地址;
请求转发
由route类型
的过滤器来完成,对pre类型过滤器获得的路由地址进行转发。
所以,Zuul过滤器可以说是Zuul实现API网关功能最为核心的部件。
(1) filterType:该函数需要返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中
默认定义了四种不同生命周期的过滤器类型,具体如下:
- pre:在请求被路由到目标服务前执行,比如权限校验、打印日志等功能;
- route:在请求被路由到目标服务时执行.
- post:在请求被路由到目标服务后执行,比如给目标服务的响应添加头信息,收集统计数据等功能;
- error:请求在其他阶段发生错误时执行.
(2) filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高。
(3) shouldFilter:返回一个boolean类型来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。
(4) run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的> 路由,或是在请求路由返回结果之后,对处理结果做一些加工等。
请求到达首先会经过pre过滤器
进行请求路径与路由规则的映射, 而后到达routing过滤器
进行路由转发, 请求就到达真正的服务提供者, 执行请求, 返回结果, 会到达post过滤器
后, 完成响应.
异常流程:
pre或者routing过滤器
出现异常, 都会直接进入error过滤器
, 在error过滤器
处理完毕后, 会将请求交给post过滤器
, 最后返回给用户.error过滤器
自己出现异常, 最终也会进入post过滤器
, 然后返回给用户.post过滤器
出现异常, 会跳转到error过滤器
, 但是与pre和routing过滤器
不同的是, 请求不会再到达post过滤器
, 而是直接返回给用户.Zuul网关的过滤器还可以做权限校验
异常处理
等功能.
移步博客: 深入浅出SpringCloud→章节 6.5.4 编写Zuul过滤器
欢迎访问个人博客: https://www.crystalblog.xyz/
备用地址: https://wang-qz.gitee.io/crystal-blog/