为什么要用微服务网关
如下图,外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与微服务通信会产生以下的问题:
- 客户端会多次请求不同的微服务,增加了客户端的复杂性。
- 存在跨域请求,在一定场景下处理比较复杂。
- 认证复杂,每个服务都需要单独认证。
- 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将很难实施。
- 某些微服务可能使用了防火墙/浏览器不友好的协议,直接访问会有一定的困难。
以上问题可借助微服务网关解决。微服务网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关。
如图,微服务网关封装了应用程序的内部结构,客户端只须跟网关交互,而无须直接调用特定微服务的接口,这样,开发就可以得到简化。不仅如此,使用微服务网关还有以下优点:
- 易于监控。可在微服务网关收集监控数据并将其推送到外部系统进行分析;
- 易于认证。可在微服务网关上进行认证,然后再将请求转发到后端的微服务,而无须再每个微服务中进行认证;
- 减少了客户端与各个微服务之间的交互次数。
Zuul
简介
Zuul
是Netflix
开源的微服务网关,它可以和Eureka
、Ribbon
、Hystrix
等组件配合使用。
Zuul
的核心是一系列的过滤器,这些过滤器可以完成以下功能:
- 身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求;
- 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图;
- 动态路由:动态地将请求路由到不同的后端集群;
- 压力测试:逐渐增加指向集群的流量,以了解性能;
- 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求;
- 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群;
- 多区域弹性:跨域
AWS Region
进行请求路由。
编写Zuul
微服务网关
- 创建 Maven 工程,
pom
文件添加已下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
- 在配置文件
application.yml
中添加:
server:
port: 8040
spring:
application:
name: microsrvice-gateway-zuul
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#关闭才可查看端点
management:
security:
enabled: false
在启动类上添加
@EnableZuulProxy
注解,声明一个Zuul
代理,该代理使用Ribbon
来定位注册在Eureka Server
中的微服务;同时,该代理还整合了hystrix
,所有经过Zuul
的请求都会在Hystrix
命令中执行。启动用户微服务,电影微服务,
访问http://localhost:8040/micorservice-consumer-movie/user/1
,请求会被转发到http://localhost:8010/user/1
访问http://localhost:8040/microservice-provider-user/1
,请求会被转发到http://localhost:8000/1
- 说明默认情况下,
Zuul
会代理所有注册到Eureka Server
的微服务,并且Zuul
的路由规则如下:http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**
会被转发到serviceId
对应的微服务。
Zuul
可以使用Ribbon
达到负载均衡的效果。Zuul
已经整合Hystrix
,访问http://localhost:8040/hystrix.stream
可以查看监控。
GET
方式访问routes
端点:http://127.0.0.1:8040/routes
:
{
"/microservice-consumer-movie/**": "microservice-consumer-movie",
"/microservice-provider-user/**": "microservice-provider-user"
}
POST
方式访问该端点,强制刷新Zuul
当前映射的路由列表。- 访问
filters
端点:http://127.0.0.1:8040/filters
:
{
"error": [
{
"class": "org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter",
"order": 0,
"disabled": false,
"static": true
}
],
"post": [
{
"class": "org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter",
"order": 1000,
"disabled": false,
"static": true
}
],
"pre": [
{
"class": "org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter",
"order": 1,
"disabled": false,
"static": true
},
{
"class": "org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter",
"order": -1,
"disabled": false,
"static": true
},
{
"class": "org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter",
"order": -2,
"disabled": false,
"static": true
},
{
"class": "org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter",
"order": -3,
"disabled": false,
"static": true
},
{
"class": "org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter",
"order": 5,
"disabled": false,
"static": true
}
],
"route": [
{
"class": "org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter",
"order": 100,
"disabled": false,
"static": true
},
{
"class": "org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter",
"order": 10,
"disabled": false,
"static": true
},
{
"class": "org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter",
"order": 500,
"disabled": false,
"static": true
}
]
}
Zuul
路由配置详解
- 自定义指定微服务的访问路径:
zuul:
routes:
microservice-provider-user: /user/**
microservice-provider-user
微服务就会被映射到路径/user/**
- 忽略指定微服务:
zuul:
ignored-services: microservice-provider-user,microservice-consumer-movie
- 忽略所有微服务,只路由指定微服务:
ignored-services: "*"
routes:
microservice-provider-user: /user/**
- 同时指定微服务的
serviceId
和路径:
zuul:
routes:
# user-route只是名称,可以任意起
user-route:
service-id: microservice-provider-user
path: /user/**
- 同时指定
path
和URL
:
zuul:
routes:
# user-route只是名称,可以任意起
user-route:
url: http://localhost:8000/
path: /user/**
但是这样有些问题,这种方式配置的路由不会作为HystrixCommand
执行,也不能使用Ribbon
来负载均衡多个URL
。
- 同时指定
path
和URL
,并且不破坏Zuul
的Hystrix
,Ribbon
特性:
zuul:
routes:
user-route:
service-id: microservice-provider-user
path: /user/**
ribbon:
eureka:
enabled: false
microservice-provider-user:
ribbon:
listOfServers: localhost:8000,localhost:8001
- 路由前缀:
- 访问
Zuul
的/api/microservice-provider-user/1
,请求转发到micorservice-provider-user
的/api/1
:
zuul:
prefix: /api
stripPrefix: false
routes:
microservice-provider-user: /user/**
- 访问
Zuul
的/user/1
,请求转发到micorservice-provider-user
的/user/1
:
zuul:
routes:
microservice-provider-user:
path: /user/**
stripPrefix: false
- 忽略某些路径:
zuul:
routes:
microservice-provider-user: /user/**
ignored-patterns: /**/admin/** #忽略所有包含admin路径的