Spring Cloud中国社区博客

Spring Cloud Zuul的URL转发和路由规则

摘要:最近开了《跟我学Spring Cloud》系列教程,由于最近比较忙,因此更新较慢。由于自己最近在研究基于Netty名为Janus的网关中间件分为janus-Server端和janus-console管控端,纳管Spring Cloud实现市面上网关85%以上的功能,将在2017年5月6号Spring Cloud中国社区北京技术沙龙分享。顺便抽时间把Spring Cloud Zuul相关的东西整理比较。在本篇文章中Spring Cloud的版本更换为Dalston.RELEASE,Spring Boot的版本为1.5.2.RELEASE。

Spring Cloud Zuul

Spring Cloud Zuul 通过与 Spring Cloud Eureka 进行整合,将自身注册到 Eureka Server中,与Eureka,Ribbon,Hystrix等整合,同时从 Eureka 中获得了所有其它微服务的实例信息。这样的设计通过把网关和服务治理整合到一起,Spring Cloud Zuul可以获取到服务注册信息,结合Ribbon,Hystrix等更好的实现路由转发,负载均衡等功能。想了解更多的内容,可以参考下面的中英文对照翻译文档。或者查看官网文档。
Spring Cloud Zuul中英文对照翻译① Spring Cloud Zuul中英文对照翻译② Spring Cloud Zuul中英文对照翻译③

Janus网关

快速搭建SC Zuul

工程目录如下图所示:

工程目录

Code地址:https://github.com/SoftwareKing/spring-cloud-study/tree/master/sc-zuul-first

Spring Cloud Zuul原始的URL转发功能

由于sc-zuul-first-provider1的代码极其简单就是一个简单的服务提供者,因此不做过多介绍。下面主要介绍sc-zuul-first-zuul-no-eureka这个工程,

URL路由转发功能

  1. 创建名为sc-zuul-first-zuul-no-eureka的maven工程,添加依赖,但注意的是该工程只有Zuul的依赖。

    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
    <?xml version="1.0"?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.xujin.sc</groupId>
    <artifactId>sc-zuul-first-zuul-no-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sc-zuul-first-zuul-no-eureka</name>
    <url>http://maven.apache.org</url>
    <!-- 引入spring boot的依赖 -->
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version>
    </parent>
    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    </properties>
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    </dependencies>
    <!-- 引入spring cloud的依赖 -->
    <dependencyManagement>
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Dalston.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
    </dependency>
    </dependencies>
    </dependencyManagement>
    <!-- 添加spring-boot的maven插件 -->
    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>
    </project>

    说明: 对于 spring-cloud-starter-zuul 依赖,我们可以通过查看它的依赖内容了解 到:该模块中不仅包含了 Netflix Zuul 的核心依赖 zuul-core,它还包含了下面这 些网关服务需要的重要依赖。
    spring-cloud-starter-hystrix:该依赖用来在网关服务中实现对微服务 转发时候的保护机制,通过线程隔离和断路器,防止微服务的故障引发 API 网关 资源无法释放,从而影响其他应用的对外服务。
    spring-cloud-starter-ribbon:该依赖用来实现在网关服务进行路由转发 时候的客户端负载均衡以及请求重试。
    spring-boot-starter-actuator :该依赖用来提供常规的微服务管理端点。另外,在Spring Cloud Zuul中还特别提供了/routes 端点来返回当前的所有路由规则。

2.主入口程序代码如下,使用@EnableZuulProxy注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package org.xujin.sc.zuul.first.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulServer;
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudZuulApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulApplication.class, args);
}
}

3.application.yml配置文件信息如下

1
2
3
4
5
server.port=8041
spring.application.name=sc-zuul-first-zuul-no-eureka
zuul.routes.api-url.path=/api-url/**
zuul.routes.api-url.url=http://localhost:8000/

该配置定义了发往 API 网关服务的请求中,所有符合/api-url/**规则的访问都 将 被 路 由 转 发 到 http://localhost:8000/ 地 址 上 , 也 就 是 说 当 我 们 访 问 http://localhost:8041/api-url/sc/order/1 可以正常的把请求的url转发到http://localhost:8000/sc/order/2 。其 中 , 配 置 属 性 zuul.routes.api-url.path 中的 api-url 部分为路由的名字,可以任意定义, 但是一组 path 和 url 映射关系的路由名要相同。

zuul.routes.api-url.url=http://localhost:8000/ 这个配置了服务提供者sc-zuul-first-provider1的URL

4.测试依次按如下顺序,把各个服务启动。
注册中心为:sc-zuul-first-eureka-server 服务提供者为:sc-zuul-first-provider1,sc-zuul-first-provider2
启动sc-zuul-first-zuul-no-eureka 上述Server启动之后,测试Case:

URL路由转发功能测试

1.当注解为@EnableZuulProxy时,测试转发。通过访问网关的URL: http://localhost:8041/api-url/sc/order/1 可以正常的把请求的url转发到http://localhost:8000/sc/order/2

网关URL转发Debug

Tips:断点跳过之后,返回结果如下,说明当使用@EnableZuulProxy注解的时候,Zuul具有URL转发调用的功能。

网关URL转发

2.关闭sc-zuul-first-zuul-no-eureka对应的服务,把主应用程序中的注解@EnableZuulProxy变为@EnableZuulServer,按第1步启动sc-zuul-first-zuul-no-eureka服务,测试。

换为@EnableZuulServer注解变为普通的Zuul Server

Tips: 可以看到上图返回结果为200,但是空白。那为什么会这样呢?后面专门对Zuul的源码分析,请读者忽略或自行查看源码。

Spring Cloud Zuul功能

大家知道Spring Cloud的服务治理的粒度是服务应用名,而如下的配置规则硬编码配置主机名和端口,由于Spring Cloud Zuul整合了Ribbon负载均衡器等因此,下面的配置方式不推荐使用比较low。

1
2
3
4
5
server.port=8041
spring.application.name=sc-zuul-first-zuul-no-eureka
zuul.routes.api-url.path=/api-url/**
zuul.routes.api-url.url=http://localhost:8000/

Spring Cloud Zuul功能案例

1.为了演示面向服务名为粒度的路由规则,新建了一个名为sc-zuul-first-zuul的工程,该工程与sc-zuul-first-zuul-no-eureka的最大的区别就是在pom.xml文件中,加入spring-cloud-starter-eureka依赖,如下注释所示。

1
2
3
4
5
6
7
8
9
10
11
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<!-- 多了eureka starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>

2.application.yml

1
2
3
4
5
6
7
8
9
10
11
server:
port: 8040
spring:
application:
name: sc-zuul-first-zuul
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true

3.主应用程序代码SpringCloudZuulApplication.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.xujin.sc.zuul.first.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
*
* @author xujin
* @EnableZuulProxy 声明一个Zuul 代理,该代理使用Ribbon软负载均衡,还整合Hystrix实现熔断
*/
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudZuulApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudZuulApplication.class, args);
}
}

4.分别依次把sc-zuul-first-eureka-server,sc-zuul-first-zuul,sc-zuul-first-provider1,
sc-zuul-first-provider2,sc-zuul-first-consumer,sc-zuul-first-hystrix-dashboard启动。
Eureka Server

Spring Cloud Zuul功能演示

1.网关的默认路由规则
说明默认情况下,Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路由规则如下:
http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/** 会被转发到serviceId对应的微服务。
http://localhost:8040/sc-zuul-first-provider/sc/order/2
默认路由规则
2.网关的负载均衡
http://localhost:8040/sc-zuul-first-provider/sc/order/2
通过网关访问服务提供者,负载均衡打出对应的日志

1
2
3
2017-04-30 18:35:37.502  INFO 3443 --- [nio-8000-exec-3] o.x.s.e.f.o.controller.OrderController  : Zuul路由到服务提供者①
2017-04-30 18:34:06.764  INFO 3444 --- [nio-8001-exec-4] o.x.s.e.f.o.controller.OrderController  : Zuul路由到服务提供者②
2017-04-30 18:35:37.251  INFO 3444 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver  : Resolving eureka endpoints via configuration

3.集成Hystrix
http://localhost:8040/hystrix.stream

Spring Cloud Zuul路由规则

指定服务路由对外访问路径

1
2
3
zuul:
routes:
sc-zuul-first-provider: /order/**

相当于把sc-zuul-first-provider映射为/order/**,访问http://localhost:8040/sc-zuul-first-provider/sc/order/2
可以等价于:http://localhost:8040/order/sc/order/2,其它路由规则,可以从官网文档中阅读尝试。