spring cloud day06Zuul-APIGateway

Posted 左沩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring cloud day06Zuul-APIGateway相关的知识,希望对你有一定的参考价值。

9.1 API Gateway

  • API Gateway是微服务架构中不可或缺的部分。API Gateway的定义以及存在的意义,Chris已经为大家描述过了,本文不再赘述,以下是链接:

中文版:http://dockone.io/article/482

英文版:https://www.nginx.com/blog/building-microservices-using-an-api-gateway/

9.2 Zuul介绍

9.2.1 zuul的功能

  • Routing in an integral part of a microservice architecture. For example, / may be mapped to your web application, /api/users is mapped to the user service and /api/shop is mapped to the shop service. Zuul is a JVM based router and server side load balancer by Netflix.
  • 路由在微服务架构的一个组成部分。 例如,/可以映射到您的Web应用程序,/ api / users映射到用户服务,并且/ api / shop映射到商店服务。 Zuul是Netflix的基于JVM的路由器和服务器端负载均衡器。
  • 其功能包括 
    • 验证
    • 见解
    • 压力测试
    • 金丝雀测试
    • 动态路由
    • 服务迁移
    • 减载
    • 安全
    • 静态响应处理
    • 主动/主动流量管理
  • Zuul的规则引擎允许规则和过滤器基本上用任何JVM语言编写,内置支持Java和Groovy。

9.2.2 Zuul的配置简述

  • 配置属性zuul.max.host.connections已被两个新属性zuul.host.maxTotalConnections和zuul.host.maxPerRouteConnections替换,默认分别为200和20。
  • 所有路由的默认Hystrix隔离模式(ExecutionIsolationStrategy)为SEMAPHORE。 如果首选此隔离模式,则可以将zuul.ribbonIsolationStrategy更改为THREAD。

9.2.3 在springcloud中使用zuul

  • Spring Cloud创建了一个嵌入式Zuul代理,以简化一个非常常见的用例开发,即UI应用程序想要代理对一个或多个后端服务的调用。此功能对于用户界面代理所需的后端服务非常有用,从而避免了对所有后端独立管理CORS和身份验证问题。
  • 要启用它,使用@EnableZuulProxy注释一个Spring Boot主类,并将本地调用转发到相应的服务。按照惯例,ID为“users”的服务将从位于/ users处的代理(带有前缀剥离)接收请求。代理使用Ribbon来定位要通过发现转发的实例,并且所有请求都在hystrix命令中执行,因此故障将显示在Hystrix指标中,一旦电路打开,代理将不会尝试联系服务。
  • 注意:Zuul启动器不包括发现客户端,因此对于基于服务ID的路由,您需要在类路径中提供其中一个(例如Eureka是一个选择)。

9.3 Zuul的基本使用

  • maven依赖
<?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>spring-cloud-microservice-study</artifactId>
        <groupId>com.clsaa.learn.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microservice-gateway-zuul</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
    </dependencies>
</project>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 启动类
package com.clsaa.learn.zuul;

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

/**
    使用@EnableZuulProxy注解激活zuul。
 * 跟进该注解可以看到该注解整合了@EnableCircuitBreaker、@EnableDiscoveryClient,是个组合注解,目的是简化配置。
 * Created by Egg on 2017/3/8.
 */
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication 
    public static void main(String[] args) 
        SpringApplication.run(ZuulApplication.class,args);
    


 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

配置文件:application.yml

spring:
  application:
    name: microservice-gateway-zuul
server:
  port: 8040
eureka:
  instance:
    hostname: localhost   # 指定该Eureka实例的主机名
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://username:password@localhost:8761/eureka
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

9.3.1 测试

  • 启动microservice-api-gateway项目。还记得我们之前访问通过http://localhost:8000/1去访问microservice-provider-user服务中id=1的用户信息吗?

我们现在访问http://localhost:8050/microservice-provider-user/1试试。会惊人地看到:

"id":1,"username":"Tom","age":12
 
  • 1

这不正是microservice-provider-user服务中id=1的用户信息吗?

所以我们可以总结出规律:访问

http://GATEWAY:GATEWAY_PORT/想要访问的Eureka服务id的小写/**
 
  • 1

,将会访问到

http://想要访问的Eureka服务id的小写:该服务端口/**
 
  • 1

9.4 自定义配置Zuul路由

上文我们已经完成了通过API Gateway去访问微服务的目的,是通过

http://GATEWAY:GATEWAY_PORT/想要访问的Eureka服务id的小写/**
 
  • 1

的形式访问的,那么如果我们想自定义在API Gateway中的路径呢?譬如想使用

http://localhost:8050/user/1
 
  • 1

就能够将请求路由到http://localhost:8000/1呢?

只需要做一点小小的配置即可:

spring:
  application:
    name: microservice-api-gateway
server:
  port: 8050
eureka:
  instance:
    hostname: gateway
  client:
    serviceUrl:
      defaultZone: http://discovery:8761/eureka/
# 下面整个树都非必须,如果不配置,将默认使用 http://GATEWAY:GATEWAY_PORT/想要访问的Eureka服务id的小写/** 路由到:http://想要访问的Eureka服务id的小写:该服务端口/**
zuul:
  routes:
    user:                                               # 可以随便写,在zuul上面唯一即可;当这里的值 = service-id时,service-id可以不写。
      path: /user/**                                    # 想要映射到的路径
      service-id: microservice-provider-user            # Eureka中的serviceId
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

9.6 如何忽略某些服务

准备工作

  1. 启动服务:microservice-discovery-eureka
  2. 启动服务:microservice-provider-user
  3. 启动服务:microservice-consumer-movie-ribbon

如果我们现在只想将microservice-consumer-movie-ribbon服务暴露给外部,microservice-provider-user不想暴露,那么应该怎么办呢?

依然只是一点小小的配置即可:

spring:
  application:
    name: microservice-api-gateway
server:
  port: 8050
eureka:
  instance:
    hostname: gateway
  client:
    serviceUrl:
      defaultZone: http://discovery:8761/eureka/
zuul:
  ignored-services: microservice-provider-user          # 需要忽视的服务(配置后将不会被路由)
  routes:
    movie:                                              # 可以随便写,在zuul上面唯一即可;当这里的值 = service-id时,service-id可以不写。
      path: /movie/**                                   # 想要映射到的路径
      service-id: microservice-consumer-movie-ribbon-with-hystrix    # Eureka中的serviceId
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 也可使用ignoredServices:服务名
  • 路由必须有一个“路径”,可以指定为ant样式模式,所以“/ myusers / ”只匹配一个级别,但“/ myusers / *”分层匹配。
  • 后端的位置可以被指定为“serviceId”(对于来自发现的服务)或“url”(对于物理位置),例如。
 zuul:
  routes:
    users:
      path: /myusers/**
      url: http://example.com/users_service
 
  • 1
  • 2
  • 3
  • 4
  • 5

9.7 启动Hystrixcommand

  • 这些简单的url路由不会作为HystrixCommand执行,也不能使用Ribbon来平衡多个URL。 要实现此目的,请指定服务路由并为serviceId配置功能区客户端(这当前需要禁用功能区中的Eureka支持:有关详细信息,请参阅上文)。
zuul:
  routes:
    users:
      path: /myusers/**
      serviceId: users

ribbon:
  eureka:
    enabled: false

users:  #这是ribion要请求的serviceID
  ribbon:
    listOfServers: http://localhost:7900,http://localhost:7901 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

9.8 使用正则表达规则路由

  • 可以使用regexmapper在serviceId和路由之间提供约定。 它使用正则表达式命名的组从serviceId提取变量并将它们注入到路由模式中。
  • regexmapper:用于routepattern转换为servicePattern
  • routepattern:路由正则表达式
  • servicePattern:service正则表达式
@Bean
public PatternServiceRouteMapper serviceRouteMapper() 
    return new PatternServiceRouteMapper(
        "(?<name>^.+)-(?<version>v.+$)",
        "$version/$name");


 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 这意味着serviceId“myusers-v1”将映射到路由“/ v1 / myusers / ”。 接受任何正则表达式,但所有命名组必须同时存在于servicePattern和routePattern中。 如果servicePattern与serviceId不匹配,则使用缺省行为。 在上面的示例中,serviceId“myusers”将映射到路由“/ myusers / ”(未检测到任何版本)。此功能默认情况下处于禁用状态,仅适用于发现的服务。
 zuul:
  ignoredPatterns: /**/admin/**
  routes:
    users: /myusers/**
 
  • 1
  • 2
  • 3
  • 4
  • This means that all calls such as “/myusers/101” will be forwarded to “/101” on the “users” service. But calls including “/admin/” will not resolve.

  • 如果你需要你的路由以保留它们的顺序,你需要使用YAML文件,因为使用属性文件将会丢失顺序。 例如:


 
  • 1
  • 如果要使用属性文件,则旧路径可能会在用户路径前面显示,导致用户路径无法访问。

9.9 zuul.prefix

  • 要向所有映射添加前缀,请将zuul.prefix设置为一个值,例如/ api。 默认情况下,在转发请求之前,从请求中删除代理前缀(使用zuul.stripPrefix = false关闭此行为)。
  • prefix和stripPrefix(依赖于prefix的使用)连用影响是全局的
  • path和stripPrefix连用影响是局部的

9.10 细节知识

9.10.1 routes

  • 如果使用@EnableZuulProxy与Spring Boot Actuator,您将启用(默认情况下)一个额外的端点,通过HTTP作为/ routes可用。 到此端点的GET将返回映射路由的列表。 POST将强制刷新现有路由(例如,如果服务目录中有更改)。

9.10.2 Strangulation Patterns (绞杀者模式)

  • 迁移现有应用程序或API时的常见模式是“扼杀”旧的端点,慢慢地用不同的实现替换它们。 Zuul代理是一个有用的工具,因为可以使用它来处理来自旧端点的客户端的所有流量,但重定向一些请求到新的端点。
 zuul:
  routes:
    first:
      path: /first/**
      url: http://first.example.com
    second:
      path: /second/**
      url: forward:/second
    third:
      path: /third/**
      url: forward:/3rd # 本地的转发
    legacy:
      path: /**
      url: http://legacy.example.com