一、概述简介

1.官网资料

https://github.com/Netflix/zuul/wiki/Getting-Started

https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.2.1.RELEASE/reference/html/#router-and-filter-zuul

2.是什么

Zuul是一种提供动态路由、监视、弹性、安全性等功能的边缘服务。
Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器。
image.png
API网关为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。它实现了请求路由、负载均衡、校验过滤、服务容错、服务聚合等功能。
image.png
Zuul包含了如下最主要的功能:
代理+路由+过滤三大功能

3.能干嘛

  1. 路由
  2. 过滤
  3. 负载均衡

网关为入口,由网关与微服务进行交互,所以网关必须要实现负载均衡的功能;
网关会获取微服务注册中心里面的服务连接地址,再配合一些算法选择其中一个服务地址,进行处理业务。
这个属于客户端侧的负载均衡,由调用方去实现负载均衡逻辑。
image.png

  1. 灰度发布(又称金丝雀发布)

起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高。
image.png
在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的A/B测试。新版本没什么问题,那么逐步扩大范围、流量,把所有用户都迁移到新版本上面来。

二、路由基本配置

1.功能

路由功能负责将外部请求转发到具体的服务实例上去,是实现统一访问入口的基础

2.新建Module模块cloud-zuul-gateway9527

3.POM

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>mscloud</artifactId>
  7. <groupId>com.atguigu.springcloud</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>cloud-zuul-gateway9527</artifactId>
  12. <dependencies>
  13. <dependency>
  14. <groupId>org.springframework.cloud</groupId>
  15. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.springframework.cloud</groupId>
  19. <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-starter-actuator</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-devtools</artifactId>
  28. <scope>runtime</scope>
  29. <optional>true</optional>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.projectlombok</groupId>
  33. <artifactId>lombok</artifactId>
  34. <optional>true</optional>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-test</artifactId>
  39. <scope>test</scope>
  40. </dependency>
  41. </dependencies>
  42. </project>

4.YAML

server:
  port: 9527

spring:
  application:
    name: cloud-zuul-gateway

eureka:
  client:
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: gateway-9527.com
    prefer-ip-address: true

5.hosts修改

127.0.0.1 myzuul.com

6.主启动类

@EnableZuulProxy

package com.atguigu.springcloud;

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

@SpringBootApplication
@EnableZuulProxy
public class Zuul_9527_StartSpringCloudApp
{
  public static void main(String[] args)
  {
   SpringApplication.run(Zuul_9527_StartSpringCloudApp.class, args);
  }
}

7.启动

  1. 三个eureka集群
  2. 一个服务提供类microservicecloud-provider-dept-8001
  3. 一个路由

image.png

8.测试

8.1 不用路由

http://localhost:8001/paymentInfo

8.2 启用路由

  1. zuul映射配置+注册中心注册后对外暴露的服务名称+rest调用地址
  2. http://myzuul.com:9527/cloud-provider-payment/paymentInfo

    三、路由访问映射规则

    1.工程microservicecloud-zuul-gateway-9527

    2.代理名称

    2.1 YAML

    before
    http://myzuul.com:9527/cloud-provider-payment/paymentInfo

    zuul:
    routes: # 路由映射配置
     mypayment.path: /mypayment/**                 #IE地址栏输入的路径
     mypayment.serviceId: cloud-provider-payment   #注册进eureka服务器的地址
    

    after
    http://myzuul.com:9527/weixin/paymentInfo

    2.2 此时问题

  3. 路由访问OK

    1. http://myzuul.com:9527/weixin/paymentInfo
  4. 原路径访问OK
    1. http://myzuul.com:9527/cloud-provider-payment/paymentInfo

      3.如果不想使用默认的路由规则,可以添加以下配置来忽略默认路由配置

4. 原有真实服务名忽略

4.1 YAML

server:
  port: 9527

spring:
  application:
    name: cloud-zuul-gateway

eureka:
  client:
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: gateway-9527.com
    prefer-ip-address: true

zuul:
  ignored-services: cloud-provider-payment
  routes: # 路由映射配置
    mypayment.serviceId: cloud-provider-payment
    mypayment.path: /weixin/**
    mysms.serviceId: cloud-provider-sms
    mysms.path: /mysms/**

4.2 上一步配置后,cloud-provider-payment就不行了

http://myzuul.com:9527/cloud-provider-payment/paymentInfo

4.3 单个具体,多个可以用”*”

zuul: 
  ignored-services: "*"
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /mydept/**

5.路由转发和负载均衡功能

5.1 服务提供者SMS短信模块

5.1.1 建模块cloud-provider-sms8008

5.1.2 POM


<?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">
    <parent>
        <artifactId>mscloud</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-sms8008</artifactId>



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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

5.1.3 YAML


server:
  port: 8008

###服务名称(服务注册到eureka名称)
spring:
    application:
        name: cloud-provider-sms

eureka:
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
      #defaultZone: http://127.0.0.1:7001/eureka,http://127.0.0.1:7002/eureka
      #defaultZone: http://eureka7001.com:7001/eureka   # eureka集群加@老本版

5.1.4 业务类


package com.atguigu.springcloud.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class SMSController
{
    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/sms")
    public String sms()
    {
        return "sms provider service: "+"\t"+serverPort;
    }
}

5.1.5 主启动


package com.atguigu.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class MainAppSMS8008
{
    public static void main(String[] args)
    {
        SpringApplication.run(MainAppSMS8008.class,args);
    }
}

5.1.6 启动8008并成功注册进eureka服务器上

image.png

5.2 修改我们的zuul服务9527

5.2.1 修改YML,体现路由转发和负载均衡


server:
  port: 9527

spring:
  application:
    name: cloud-zuul-gateway

eureka:
  client:
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: gateway-9527.com
    prefer-ip-address: true

zuul:
  #ignored-services: cloud-provider-payment
  routes: # 路由映射配置
    mypayment.serviceId: cloud-provider-payment
    mypayment.path: /weixin/**
    mysms.serviceId: cloud-provider-sms
    mysms.path: /mysms/**

由于Zuul自动集成了Ribbon和Hystrix,所以Zuul天生就有负载均衡和服务容错能力

5.3 测试

负载均衡:
http://myzuul.com:9527/weixin/paymentInfo
路由转发:
http://myzuul.com:9527/mysms/sms

微信服务找8001/8002

短信服务找8008

5.4 设置统一公共前缀

5.4.1 YML

zuul: 
  prefix: /atguigu
  ignored-services: "*"
  routes: 
    mydept.serviceId: microservicecloud-dept
    mydept.path: /mydept/**

http://myzuul.com:9527/atguigu/weixin/paymentInfo
http://myzuul.com:9527/atguigu/mysms/sms
http://myzuul.com:9527/atguigu/cloud-provider-payment/paymentInfo

5.5 最后YML

server:
  port: 9527

spring:
  application:
    name: cloud-zuul-gateway

eureka:
  client:
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: gateway-9527.com
    prefer-ip-address: true

zuul:
  #ignored-services: cloud-provider-payment
  prefix: /atguigu
  routes: # 路由映射配置
    mypayment.serviceId: cloud-provider-payment
    mypayment.path: /weixin/**
    mysms.serviceId: cloud-provider-sms
    mysms.path: /mysms/**

四、查看路由信息

1.POM

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.YML


# 开启查看路由的端点
management:
  endpoints:
    web:
      exposure:
        include: 'routes'

3.查看路由详细信息

http://localhost:9527/actuator/routes

五、过滤器

1. 功能

过滤功能负责对请求过程进行额外的处理,是请求校验过滤及服务聚合的基础。

2.过滤器的生命周期

image.png

3.ZuulFilter

3.1 过滤类型

  1. pre:在请求被路由到目标服务前执行,比如权限校验、打印日志等功能;
  2. routing:在请求被路由到目标服务时执行
  3. post:在请求被路由到目标服务后执行,比如给目标服务的响应添加头信息,收集统计数据等功能;
  4. error:请求在其他阶段发生错误时执行。

    3.2 过滤顺序

    数字小的先执行

    3.3 过滤是否开启

    shouldFilter方法为true走

    3.4 执行逻辑

    自己的业务逻辑

    4 案例Case

    前置过滤器,用于在请求路由到目标服务前打印请求日志

    4.1业务代码

    ```java

package com.atguigu.springcloud.Filter;

import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest; import java.util.Date;

@Component @Slf4j public class PreLogFilter extends ZuulFilter { @Override public String filterType() { return “pre”; }

@Override
public int filterOrder()
{
    return 1;
}

@Override
public boolean shouldFilter()
{
    return true;
}

@Override
public Object run() throws ZuulException
{
    RequestContext requestContext = RequestContext.getCurrentContext();
    HttpServletRequest request = requestContext.getRequest();
    String host = request.getRemoteHost();
    String method = request.getMethod();
    String uri = request.getRequestURI();
    //log.info("=====> Remote host:{},method:{},uri:{}", host, method, uri);
    System.out.println("********"+new Date().getTime());
    return null;
}

}

<a name="cu7Cr"></a>
### 4.2测试
[http://myzuul.com:9527/atguigu/mysms/sms](http://myzuul.com:9527/atguigu/mysms/sms)<br />在调用8008之前会打印日志
<a name="uMfEj"></a>
### 4.3开关,YML配置
```yaml
zuul:
  PreLogFilter:
    pre:
      disable: true