Spring Cloud 网关 Zuul

  由于后起之秀 Gateway 的诞生,不建议在新项目中再使用 Zuul。

序言

  当客户端发出一些对微服务获取资源的请求到后端,这些请求将通过 FS、 Nginx 等设施的路由和负载均衡分配并转发到各个不同的服务实例上。为了让这些设施能够正确路由与分发请求,运维人员需要手工维护这些路由规则与服务实例列表, 当有实例增减或是 IP 地址变动等情况发生的时候,也需要手工地去同步修改这些信息以保持实例信息与中间件的一致。当系统规模不断增大时,这些看似简单的维护任务会变得越来越麻烦,且配置出错概率也会增加。

  很显然,上述做法并不可取,因此,我们需要一套机制来有效降低维护路由规则与服务实例列表的难度。

  对于某些服务的权限校验(如用户登录状态的校验),若突然发现校验逻辑有个 BUG 需要修复,或者需要对其做一些扩展和优化,此时就不得不去每个应用里修改这些逻辑,这样的修改不仅会引起开发入员的抱怨,更会加重测试人员的负担。所以,我们也需要一套机制,能够很好地解决微服务架构中,对于微服务接口访问时各前置校验的冗余问题。

  这时候就可以使用 API 网关,Zuul 就是一种网关。

Zuul:API 网关

  Spring Cloud 中了提供了基于 Netflix Zuul 实现的 API 网关组件: Zuul。

  对于路由规则与服务实例的维护问题,Zuul 通过与 Eureka 进行整合,将自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获得了所有其他微服务的实例信息。这样将维护服务实例的工作交给了服务治理框架自动完成,不再需要人工介入。
  而对于路由规则的维护, Zuul 默认会将通过以服务名作为 ContextPath 的方式来创建路由映射。大部分情况下,这样的默认设置已经可以实现开发人员大部分的路由需求,大大减少了运维的工作量。

快速入门

① 添加依赖

  首先,我们新建一个名为zuul-gateway的模块,并在pom.xml文件加入下面的依赖:

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

② 添加注解

  新建启动类并添加@EnableZuulProxy注解:

1
2
3
4
5
6
7
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class);
}
}

③ 创建配置文件

  在resources下创建application.yml文件,并添加:

1
2
3
4
5
6
7
server:
port: 10010
zuul:
routes:
servername:
path: /user-service/**
url: http://127.0.0.1:8081

  其中 :

  • servername代表服务名,可以随意命名
  • path代表请求路径
  • url代表请求路径转发的服务器

  简单来说,启动 Zuul 服务器后, 我们访问http://127.0.0.1:10010/user-service/下的请求都会转发到http://127.0.0.1:8081的服务器,也即我们前面配置的user-service服务器。

④ 测试

  访问http://127.0.0.1:10010/user-service/user/1进行测试,输入结果如下:

1
{"id":1,"username":"lucy","password":"123","name":"章总","telephone":0}

问题与优化

  我们发现,在application.yml中对转发的服务进行硬编码,不利于维护,而且,若有集群存在时无法实现负载均衡。

路由配置

  对 Zuul 而言,不应该直接去访问具体的服务器,而是应该先去 Eureka 注册中心拉去相关的服务,然后再进行访问。我们称其为面向服务的路由
  因此我们需要将 Zuul 也注册到 Eureka 中,首先在zuul-gateway模块添加 Euraka 的依赖;

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

  然后修改application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 10010
spring:
application:
name: zuul-gateway
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
zuul:
routes:
servername:
path: /user-service/**
serviceId: user-service

  这样让 Zuul 去访问 Eureka 的提供的服务 Id 即可。
  由于servername没啥用处,所有我们可以直接配置serviceId和路径path

1
2
3
zuul:
routes:
user-service: /user-service/**

  其中user-service是服务 Id,而/user-service/**是映射的路径。

默认的路由配置

  大多数情况下,路由的名称和服务名相同。
  由于这样的配置太过于常见,所以上面的配置可以全部不写,全部不写,全部不写!!!
  Zuul 默认转换 Eureka 注册中心所有的服务,并且还实现了反向代理和负载均衡。

路由前缀

  我们可以通过以下配置来指定路由前缀:

1
2
zuul:
prefix: /api

  这样在发起请求时,路由就要以/api开头

自定义配置

  当然,若觉得 Zuul 默认配置的路径太长或者某些服务不想对外界暴露(只提供服务间调用),则可以进行自定义配置:

1
2
3
4
5
zuul:
routes:
user-service: /user/**
ignored-services:
- consumer

  这么配置将 Eureka 提供的user-service服务映射路径缩短为/user/**
  ignored-services参数代表对外界关闭的服务列表(一个 Set 集合,用-分隔),这里我们将consumer服务对外界关闭了。

过滤器

  Zuul 作为网关的一个重要功能就是实现请求的鉴权,这个动作往往是通过 Zuul 提供的过滤器来实现。

负载均衡和熔断

  Zuul 中已默认集成了 Ribbon 负载均衡和 Hystix 熔断机制。
  但是,所有的超时策略都走的默认值,如熔断超时时间只有 1 S,很容易就触发了。
  因此,我们最好手动配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
hystrix:
commond:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000

ribbon:
CoonectionTimeout: 500 # 连接超时时长
ReadTimeout: 2000 # 读取超时时长
MaxAutoRetries: 0 # 当前服务重试次数
MaxAutoRetriesNextServer: 0 # 切换服务重试次数

注意哦:Ribbon 的超时时长为(连接超时时长 + 读取超时时长) X 2,且必须小于 Hystrix 时长。

参考

0%