SpringCloud进击 | 五浅出:服务网关 - 路由(Zuul Router)【Finchley版本】

1.前言

路由,微服务体系结构的一个组成部分,是 Netflix 基本 JVM 的路由器和服务端的负载均衡器。形象一点就是我们经常会看到的像请求路径:/api/user 映射到用户服务,/api/cart 映射到购物车服务。是的,路由(/)可以映射到你的Web应用程序,到某个模块,到某个具体的服务。

我们知道,在微服务中,后台服务往往不是直接开放给调用者,而是通过 Gateway 网关根据请求的 URL,路由到相应的服务。这种情况下,Gateway一般都封装了一套API,当添加 Gateway API 网关后,在第三方调用者和服务提供方之间就创建了一面无形的墙,这面墙直接与调用方通信,进行权限控制后将请求均衡分发给后台服务端。所以,我们看似完成的微服务架构其实还是少考虑了一个问题,这也是我们这节的主要内容,即,外部的应用怎么来访问内部各种各样的微服务呢?

 

2.准备

使用并分别启动前几节我们已经创建好的以下模块的启动类:

  • 服务注册中心:wei-eureka-server,端口号:8090(无需修改,正常启动)
  • 服务提供者:wei-service-provider,端口号:8010(无需修改,正常启动)
  • 服务消费者:wei-consumer-ribbon,端口号:8022(以端口号正常启动)
  • 服务网关:wei-gateway-zuul,端口号:8040(本节新建)

这里的服务消费者,我们直接把之前在浅出 第二节 做好的Demo拿来用。除了修改端口号以示区别外,其它不用动。

 

3.进击

3.1.服务网关之路由/映射

在原有项目上创建一个新的基于 Spring Boot 模块,并起名为 wei-gateway-zuul。创建过程与第一节创建模块的过程类似。但在 Dependencies 选择依赖时需要注意,选择左侧的 Cloud Routing 后,这里需要钩上 Zuul 项。

所以,最终我们需要勾选左侧 Cloud Discovery 的 Eureka Discovery,和左侧 Cloud Routing 的 Zuul,以及左侧 Web 的 Web 依赖。

3.1.1.pom.xml 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.wei</groupId>
    <artifactId>wei-gateway-zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>wei-gateway-zuul</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>

 

3.1.2.application.yml 配置

server:
  port: 8040    # 自定义程序启动端口
spring:
  application:
    name: wei-gateway-zuul    # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8090/eureka/    # 指定进行服务注册的地址

 

3.1.3.启动类

package com.wei;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

/**
 * 注解@EnableZuulProxy,开启Zuul功能,自带熔断
 */
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class WeiGatewayZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(WeiGatewayZuulApplication.class, args);
    }
}

 

3.1.4.测试

服务注册中心查看服务,如下,注册成功。

【Eureka Server】

首先,可以正常访问服务提供者:http://localhost:8010/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010

其次,也可以正常通过服务消费者消费服务:http://localhost:8022/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]

 

那么,加上 Zuul 路由后会有什么不一样呢?

由于 Spring Cloud Zuul 在整合了 Eureka 之后,具备默认的服务路由功能,即:当我们构建 Zuul 的实现 wei-gateway-zuul 模块,启动并注册到 Eureka 之后,服务网关会发现上面我们启动的两个服务 wei-service-provider 和 wei-consumer-ribbon,这时候 Zuul 就会创建两个路由规则。每个路由规则都包含两部分,一部分是外部请求的匹配规则,另一部分是路由的服务ID(application.name配置):

  • 转发到 wei-service-provider 服务提供者的请求规则为 /wei-service-provider/**
  • 转发到 wei-consumer-ribbon 服务消费者的请求规则为 /wei-consumer-ribbon/**

不用修改 Zuul模块的 application.yml 配置文件,执照这个规则,我们来验证一下:

访问:http://localhost:8040/wei-service-provider/demo/info?name=tester,输出:

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010

访问:http://localhost:8040/wei-consumer-ribbon/demo/info?name=tester,输出:

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]

 

注意,都是8040端口下,加上应用模块的名字哈。

到这里,验证成功。一个基于 Spring Cloud Zuul 的默认的服务网关就已经构建完毕。

 

但是,或者,你也发现,如果每次都使用服务名,可能不太好,它们的名字或长或短,也可能会使调用变得复杂。所以,我们需要自定义服务映射地址,Zuul 也提供了自定义服务映射地址的功能,我们只需修改相关配置就能实现。

 

3.2.自定义服务映射地址

3.2.1.服务名称映射

改造 application.yml 配置文件:

server:
  port: 8040    # 自定义程序启动端口
spring:
  application:
    name: wei-gateway-zuul    # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8090/eureka/    # 指定进行服务注册的地址
zuul:
  routes:    # 配置路由映射
    wei-service-provider: /providerGroup/**    # 服务名称映射。给指定的服务做映射,当前配置是将/wei-service-provider/**映射为/providerGroup/**

通过配置项 zuul.routes.applicationName 就可以给指定的服务添加地址映射。

配置完成后,重启 Zuul 模块的启动类,并访问地址:http://localhost:8040/providerGroup/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010

有没有,其结果与之前的 http://localhost:8040/wei-service-provider/demo/info?name=tester 一样。

 

3.2.2.path绑定映射

我们也可以使用 path 属性自定义映射地址,同样只需改造 application.yml 配置文件:

server:
  port: 8040    # 自定义程序启动端口
spring:
  application:
    name: wei-gateway-zuul    # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8090/eureka/    # 指定进行服务注册的地址
zuul:
  routes:    # 配置路由映射
    wei-service-provider: /providerGroup/**    # 服务名称映射。给指定的服务做映射,当前配置是将/wei-service-provider/**映射为/providerGroup/**
    consumerGroup:    # 保证唯一
      serviceId: wei-consumer-ribbon    # 给指定的服务做映射
      path: /consumerGroup/**    # path绑定映射。配置映射的路径,当前配置是将/wei-consumer-ribbon/**映射为/consumerGroup/**

配置完成后,重启 Zuul 模块的启动类,并访问地址:http://localhost:8040/consumerGroup/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]

同样的,其结果与之前的 http://localhost:8040/wei-consumer-ribbon/demo/info?name=tester 一样。

 

3.2.3.url绑定映射

除了上面两种方法,还可以使用 url 属性直接绑定对应 url。将上面的配置 serviceId: wei-consumer-ribbon 改造为 url: http://localhost:8022/,然后重启启动类即可。

server:
  port: 8040    # 自定义程序启动端口
spring:
  application:
    name: wei-gateway-zuul    # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8090/eureka/    # 指定进行服务注册的地址
zuul:
  routes:    # 配置路由映射
    wei-service-provider: /providerGroup/**    # 服务名称映射。给指定的服务做映射,当前配置是将/wei-service-provider/**映射为/providerGroup/**
    consumerGroup:    # 保证唯一
      url: http://localhost:8022/    # url绑定映射
      #serviceId: wei-consumer-ribbon    # 给指定的服务做映射
      path: /consumerGroup/**    # path绑定映射。配置映射的路径,当前配置是将/wei-consumer-ribbon/**映射为/consumerGroup/**

配置完成后,重启 Zuul 模块的启动类,并访问地址:http://localhost:8040/consumerGroup/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]

其结果也完全一样。

这三种方式都可以指定服务映射地址,需要注意的是这些简单的URL路由不会被执行为 HystrixCommand,也不能使用 Ribbon 对多个URL进行负载均衡。

 

3.3.实现负载均衡

如果想要达到负载均衡的效果,需要使用 serviceId 配置的方式再加上 ribbon.listOfServers 配置。改造 application.yml

server:
  port: 8040    # 自定义程序启动端口
spring:
  application:
    name: wei-gateway-zuul    # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8090/eureka/    # 指定进行服务注册的地址
zuul:
  routes:    # 配置路由映射
    wei-service-provider: /providerGroup/**    # 服务名称映射。给指定的服务做映射,当前配置是将/wei-service-provider/**映射为/providerGroup/**
    consumerGroup:    # 保证唯一
      #url: http://localhost:8022/    # url绑定映射
      serviceId: wei-consumer-ribbon    # 给指定的服务做映射
      path: /consumerGroup/**    # path绑定映射。配置映射的路径,当前配置是将/wei-consumer-ribbon/**映射为/consumerGroup/**
ribbon:
  eureka:
    enabled: false    # 在eureka中禁用 ribbon 的负载均衡
wei-consumer-ribbon:
  ribbon:    # 给配置serviceId对应的服务指定ribbon负载均衡,从listOfServers配置的服务地址中分配服务,多个用半角逗号分隔
    listOfServers: http://localhost:8010/, http://localhost:8011/

给配置serviceId对应的服务指定ribbon负载均衡,从listOfServers配置的服务地址中分配服务,多个用半角逗号分隔。

改造完成后,重启 Zuul 的实现模块的启动类。然后还需要再开一个服务提供者实例,修改 wei-service-provider 的端口号为8011,运行其启动类。这样,此时会有两个服务提供者 8010、8011。

访问URL:http://localhost:8040/consumerGroup/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8011

可以看到,通过 Zuul 调用,和之前的 第二节 配置 Ribbon负载均衡效果一样,浏览器输出的日志在端口为8010和8011的服务之间切换打印,默认轮询。

 

3.4.添加前缀映射

改造 application.yml,配置属性:zuul.prefix,指定路由前缀。

server:
  port: 8040    # 自定义程序启动端口
spring:
  application:
    name: wei-gateway-zuul    # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8090/eureka/    # 指定进行服务注册的地址
zuul:
  routes:    # 配置路由映射
    wei-service-provider: /providerGroup/**    # 服务名称映射。给指定的服务做映射,当前配置是将/wei-service-provider/**映射为/providerGroup/**
    consumerGroup:    # 保证唯一
      #url: http://localhost:8022/    # url绑定映射
      serviceId: wei-consumer-ribbon    # 给指定的服务做映射
      path: /consumerGroup/**    # path绑定映射。配置映射的路径,当前配置是将/wei-consumer-ribbon/**映射为/consumerGroup/**
  prefix: /api
ribbon:
  eureka:
    enabled: false    # 在eureka中禁用 ribbon 的负载均衡
wei-consumer-ribbon:
  ribbon:    # 给配置serviceId对应的服务指定ribbon负载均衡,从listOfServers配置的服务地址中分配服务,多个用半角逗号分隔
    listOfServers: http://localhost:8010/, http://localhost:8011/

这里,我们设置了路由前缀 /api,这将会给对应服务的所有映射添加该指定的前缀。

访问URL:http://localhost:8040/api/consumerGroup/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8011

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010

打印结果与上面 3.3.实现负载均衡 不加前缀的结果一致。同样也有负载均衡的效果。

通过zuul.stripPrefix=false去关闭添加前缀的行为,关闭的前缀只能是zuul.prefix设置的前缀

 

4.总结

Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。
Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。

 

参考资料:
https://springcloud.cc/spring-cloud-netflix.html
http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_router_and_filter_zuul


本节源码:https://github.com/itanping/wei-springcloud/tree/master/chapter06-zuul


下一节,请继续关注:SpringCloud进击 | 六浅出:服务网关 - 过滤器(Zuul Filter)【Finchley版本】

 

5.物语

SpringCloud进击 | 一浅出:服务注册与发现(Eureka)【Finchley版本】
SpringCloud进击 | 二浅出:服务消费者(Ribbon+REST)【Finchley版本】
SpringCloud进击 | 三浅出:服务消费者(Feign)【Finchley版本】
SpringCloud进击 | 四浅出:断路器与容错(Hystrix)【Finchley版本】
SpringCloud进击 | 五浅出:服务网关 - 路由(Zuul Router)【Finchley版本】
SpringCloud进击 | 六浅出:服务网关 - 过滤器(Zuul Filter)【Finchley版本】
SpringCloud进击 | 七浅出:配置中心(Git配置与更新)【Finchley版本】
SpringCloud进击 | 一深入:配置中心(服务化与高可用)【Finchley版本】
SpringCloud进击 | 二深入:配置中心(消息总线)【Finchley版本】
SpringCloud进击 | 三深入:服务链路跟踪(Spring Cloud Sleuth)【Finchley版本】
SpringCloud进击 | 四深入:服务链路跟踪(Sleuth+Zipkin+RabbitMQ整合)【Finchley版本】
SpringCloud进击 | 五深入:断路器监控(Hystrix Dashboard)【Finchley版本】
SpringCloud进击 | 六深入:断路器聚合监控(Hystrix Turbine)【Finchley版本】
SpringCloud进击 | 七深入:高可用的服务注册中心【Finchley版本】

项目说明 该项目是一个典型的由Spring Cloud管理的微服务项目,主要包括如下模块 micro-service-cloud─────────────────顶层项目 ├──cloud-service-core───────────────基础核心模块 ├──cloud-service-tools──────────────全局通用工具类 ├──cloud-service-reids──────────────Redis二次封装 ├──cloud-eureka-server──────────────服务注册中心[8761] ├──cloud-turbine-server─────────────断路器聚合监控[8769] ├──cloud-zipkin-server──────────────链路追踪监控[9411] ├──cloud-zuul-server────────────────第一代服务网关(Zuul)[8080] ├──cloud-gateway-server─────────────第二代服务网关(Gateway)[8080] ├──cloud-modules-app────────────────App微服务模块 ├───────modules-app-user────────────App用户服务模块[努力更新中] ├───────modules-app-doctor──────────App医生服务模块[努力更新中] ├──cloud-modules-service────────────微服务通用服务模块 ├───────mongodb-file-service────────Mongodb文件服务模块[11010] ├───────redis-delay-service─────────延迟消费服务模块[11020] ├──cloud-modules-web────────────────Web微服务模块 ├───────modules-web-security────────Web医生服务模块[12010] ├───────modules-web-user────────────Web用户服务模块[12020] ├──cloud-modules-wechat─────────────Wechat微服务模块 ├───────modules-wechat-user─────────Wechat用户服务模块[努力更新中] └───────modules-wechat-doctor───────Wechat医生服务模块[努力更新中] 修改日志 修改日志 修改人 修改日期 版本计划 V1.0 刘岗强 2019-01-07 项目初始化 V1.1 刘岗强 待定 新增自动问答 项目介绍 基于Spring Cloud Finchley SR2 Spring Boot 2.0.7的最新版本。 核心基础项目内实现类自定义的权限注解,配合RBAC权限模型+拦截器即可实现权限的控制,具体的参考项目中的实现。同时也封装了一些顶层类和结果集等。 注册中心实现高可用配置,详情见eureka的one、two、three三个配置文件,摘要如下。 ------------------------------------------配置节点一---------------------------------------------- server: port: 8761 spring: application: name: cloud-eureka-server eureka: instance: hostname: cloud.server.one prefer-ip-address: true instance-id: ${spring.cloud.client.ip-address}:${server.port}:${spring.application.name} client: healthcheck: enabled: true register-with-eureka: false fetch-registry: false service-url: defaultZone: http://cloud.server.two:8762/eureka/,http://cloud.server.three:8763/eureka/ ------------------------------------------配置节点二----------------------------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值