八、微服务网关之Zuul

为什么要用微服务网关

如下图,外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与微服务通信会产生以下的问题:

  • 客户端会多次请求不同的微服务,增加了客户端的复杂性。
  • 存在跨域请求,在一定场景下处理比较复杂。
  • 认证复杂,每个服务都需要单独认证。
  • 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将很难实施。
  • 某些微服务可能使用了防火墙/浏览器不友好的协议,直接访问会有一定的困难。

用户请求多个微服务

以上问题可借助微服务网关解决。微服务网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关。
如图,微服务网关封装了应用程序的内部结构,客户端只须跟网关交互,而无须直接调用特定微服务的接口,这样,开发就可以得到简化。不仅如此,使用微服务网关还有以下优点:

  • 易于监控。可在微服务网关收集监控数据并将其推送到外部系统进行分析;
  • 易于认证。可在微服务网关上进行认证,然后再将请求转发到后端的微服务,而无须再每个微服务中进行认证;
  • 减少了客户端与各个微服务之间的交互次数

使用微服务网关


Zuul简介

ZuulNetflix开源的微服务网关,它可以和EurekaRibbonHystrix等组件配合使用。

Zuul的核心是一系列的过滤器,这些过滤器可以完成以下功能:

  • 身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求;
  • 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图;
  • 动态路由:动态地将请求路由到不同的后端集群;
  • 压力测试:逐渐增加指向集群的流量,以了解性能;
  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求;
  • 静态响应处理:在边缘位置直接建立部分响应,从而避免其转发到内部集群;
  • 多区域弹性:跨域AWS Region进行请求路由。

编写Zuul微服务网关

  1. 创建 Maven 工程,pom文件添加已下依赖:
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  1. 在配置文件application.yml中添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
server:
port: 8040
spring:
application:
name: microsrvice-gateway-zuul
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
#关闭才可查看端点
management:
security:
enabled: false
  1. 在启动类上添加@EnableZuulProxy注解,声明一个Zuul代理,该代理使用Ribbon来定位注册在Eureka Server中的微服务;同时,该代理还整合了hystrix,所有经过Zuul的请求都会在Hystrix命令中执行。

  2. 启动用户微服务,电影微服务,

    访问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对应的微服务。
  1. Zuul可以使用Ribbon达到负载均衡的效果。
  2. Zuul已经整合Hystrix,访问http://localhost:8040/hystrix.stream可以查看监控。
    7.
  • GET方式访问routes端点:http://127.0.0.1:8040/routes:
1
2
3
4
{
"/microservice-consumer-movie/**": "microservice-consumer-movie",
"/microservice-provider-user/**": "microservice-provider-user"
}
  • POST方式访问该端点,强制刷新Zuul当前映射的路由列表。
  • 访问filters端点:http://127.0.0.1:8040/filters:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
{
"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路由配置详解

  1. 自定义指定微服务的访问路径:
1
2
3
zuul:
routes:
microservice-provider-user: /user/**

microservice-provider-user微服务就会被映射到路径/user/**

  1. 忽略指定微服务:
1
2
zuul:
ignored-services: microservice-provider-user,microservice-consumer-movie
  1. 忽略所有微服务,只路由指定微服务:
1
2
3
ignored-services: "*"
routes:
microservice-provider-user: /user/**
  1. 同时指定微服务的serviceId和路径:
1
2
3
4
5
6
zuul:
routes:
# user-route只是名称,可以任意起
user-route:
service-id: microservice-provider-user
path: /user/**
  1. 同时指定pathURL:
1
2
3
4
5
6
zuul:
routes:
# user-route只是名称,可以任意起
user-route:
url: http://localhost:8000/
path: /user/**

但是这样有些问题,这种方式配置的路由不会作为HystrixCommand执行,也不能使用Ribbon来负载均衡多个URL

  1. 同时指定pathURL,并且不破坏ZuulHystrix,Ribbon特性:
1
2
3
4
5
6
7
8
9
10
11
zuul:
routes:
user-route:
service-id: microservice-provider-user
path: /user/**
ribbon:
eureka:
enabled: false
microservice-provider-user:
ribbon:
listOfServers: localhost:8000,localhost:8001
  1. 路由前缀:
  • 访问Zuul/api/microservice-provider-user/1,请求转发到micorservice-provider-user/api/1:
1
2
3
4
5
zuul:
prefix: /api
stripPrefix: false
routes:
microservice-provider-user: /user/**
  • 访问Zuul/user/1,请求转发到micorservice-provider-user/user/1:
1
2
3
4
5
zuul:
routes:
microservice-provider-user:
path: /user/**
stripPrefix: false
  1. 忽略某些路径:
1
2
3
4
zuul:
routes:
microservice-provider-user: /user/**
ignored-patterns: /**/admin/** #忽略所有包含admin路径的

该文章摘自《Spring Cloud 与 Docker 微服务架构实战(第二版)》

以上

LeoQin wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
0%