春の雲Zuul概要

APIゲートウェイは何ですか

言葉は、実際にゲートウェイハードウェアの概念です。ファイアウォールやプロキシサーバーやその他の関連する機能は、と統合する傾向があるので、そのため、定義により、ネットワークゲートウェイは、ネットワークのエッジに表示されます。ホームネットワークおよび小規模企業では、ブロードバンドルータは、通常、ネットワークのゲートウェイとして機能します。また、ご自宅やビジネス機器やインターネット接続。ゲートウェイはルータの最も重要な機能である、ルータ、ゲートウェイの最も一般的なタイプです。

我々は話今日はのように行う、ゲートウェイルータ(冗談)ではない自然なアプリケーション開発の入り口を議論-API各サービスコール、APIゲートウェイと呼ばれる全てのサービスの入り口を、。

ほとんどのマイクロサービスの実装では、内部のマイクロサービスエンドポイントが外部に露出していません。彼らは、民間のサービスのために予約されています。公共サービスのセットは、クライアントのオープンにAPIゲートウェイを使用します。そうする多くの理由があります。

  1. クライアントはマイクロサービスの唯一の選択グループを必要とします。
  2. サービスエンドポイント上のクライアント固有の変換を達成することは困難。
  3. 複数のクライアントを回避するために特に必要なデータ重合は、帯域幅が制限された環境、必要な中間ゲートウェイを呼び出す場合。
  4. サービスインスタンスの数及びそれらの位置(ホスト+ポート)動的変化。
  5. あなたは顧客固有の戦略を適用する場合、単一の場所ではなく、複数の場所にそれらを適用することは容易です。この例では、クロスドメインアクセスポリシーです。

ゲートウェイの利点を使用します

  1. マイクロサービスアーキテクチャパーティションの背後にあるクライアントおよびゲートウェイが単離されます。
  2. お客様は、位置特定サービスを心配する必要はありません。
  3. あなたは顧客固有の戦略を適用する場合、単一の場所ではなく、複数の場所にそれらを適用することは容易です。この例では、クロスドメインアクセスポリシーです。
  4. 各顧客は、最高のAPIエンドを提供するために、
  5. 削減要求/往復。
  6. クライアントAPIゲートウェイを簡素化するために集約ロジックによって移動。

短所

  1. ゲートウェイAPIは、複雑さが管理するマイクロダイナミック・サービス・アーキテクチャの別の部分で増加しました。
  2. 直接呼び出しと比較することにより、応答時間が増加するため、追加のネットワークは、APIゲートウェイを介してジャンプしなければなりませんでした。
  3. 実施形態あまりにも危険なポリマー層内のロジック。

また、マイクロサービスシステムでは、分割及び外国サービスの各サブサービスであるとすると、単一の機能である、単一の機能レイアウトの全体的な枠組みの下で、各インタフェースのアドレスが外部に設けられて設けられ、ユーザ中心のように、同じでなければなりませんサービスは、すべてのインターフェイスがある必要がありapi.userCenter.com、以下:

https://api.userCenter.com/user/getUser
https://api.userCenter.com/dept/get

しかし、いないでしばらくapi.userCenter.comしばらくして、下記の別のアドレスに行って、アドレスが同じでない場合、それは2つのサービスの代わりに、1でなければなりません。

:だからゲートウェイの中心的な役割である統一されたインタフェースのルートは

存在のゲートウェイ意味がサービスを提供することで、ゲートウェイとして、それが何をするか、能力を持っている必要がありますか?

リクエストを受信1.:究極の能力は、ゲートウェイが要求を受信し、その後、転送要求うち、最初、それはMVCの能力を持っている必要がありますが、それはサーブレットを達成する必要があります。

2.要求:ゲートウェイは、他のサービスに要求を転送する必要があり、それは、要求を送信する機能を持っている必要があり、それは、HTTP関連メソッドを達成する必要があります。

3.フィルタの要求:ゲートウェイその後、彼は、フィルタ要求する能力を持っていますが、要求された許可、ログや他の操作を提供するために、それはフィルタを実装する必要があります。

4.サービスのリストを取得します:ゲートウェイは、それはそれはレジストリからサービスのリストを取得する必要があることをマイクロサービスアップビューセットのアーキテクチャの観点から、ルーティングアドレスを取得する必要があり、ルーティング機能を提供します。

5.ルーティング構成:次に、ルーティング動作を実現するゲートウェイ、関係を対応する要求経路とサービスを設定する必要があります。

Zuul

春クラウドZuul主な機能は、ロードバランシング、リバースプロキシ、認証局、ダイナミックルーティング、モニタリング、耐障害性、セキュリティ、および他のエッジサービスを提供することです。その主な役割は、メインクラスタサービスは、高い再利用性とテスト容易性を持つことができるように、権限がサービスレベルのルーティング非ビジネスロジックにこれらの重いコンテンツの移動を制御する一方で、フロントドアの役割を保護するためのマイクロアーキテクチャのためのサービスを提供することです。

ノーNetflixのZuulマイクロサービスコール:

マイクロサービスコールとNetflixのZuul:

使用NetflixのZuul + Netflixのユーレカマイクロサービスコール:

Zuul例を構築するためのゲートウェイ

します。https:ユーレカプロジェクトと装うが、我々はに基づいて構築されてきたこれまでの例を呼び出す//github.com/rickiyang/SpringCloud-learnが、我々はZuulゲートウェイセンターを構築し続けています。

POMファイルで新しいZuul構成:

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

次のように全体的な構成は以下のとおりです。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.rickiyang.learn</groupId>
        <artifactId>springcloud-learn</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.rickiyang.learn</groupId>
    <artifactId>zuul-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>zuul-server</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <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.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </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>

</project>

スタートクラス注釈オープンZuulさん:

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

@EnableDiscoveryClient
@EnableZuulProxy
@SpringBootApplication
public class ZuulServerApplication {

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

}

ユーレカで構成プロパティを追加するための設定ファイル:

server:
  port: 8767
spring:
  application:
    name: zuul-server
  main:
    allow-bean-definition-overriding: true
eureka:
  client:
    service-url:
      defaultZone : http://localhost:8761/eureka/,http://localhost:8762/eureka/,http://localhost:8763/eureka/
    instance:
      lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
      lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
      prefer-ip-address: true     # 访问的路径变为IP地址

这样一个api网关就简单的搭建好了。食用方式:先启动Eureka-server,接着启动Eureka-client,最后启动zuul-server。

首先验证一下 Eureka-client 接口是否可用:

http://localhost:8766/hello/xiaoming

可用的情况下再来使用Zuul调用,网关 zuul 默认转发地址是:

http://网关IP:网关端口/被转发的服务application.name/要访问的接口

本示例中就是:

http://localhost:8767/eureka-client/hello/xiaoming

如果我们觉得服务名:eureka-client 太长了,或者是不想暴露服务名,想用简洁的字段来替代,可以用如下配置:

zuul:
  routes:
    eureka-client:
      path: /client1/**
      serviceId: eureka-client

那么访问服务的url就变为:

http://localhost:8767/client1/hello/xiaoming

这样替换之后,如果该路径中有一些url已经被业务方调用,无法替换,那么需要把这些url排除:

zuul:
  #所有服务路径前统一加上前缀
  prefix: /api
  # 排除某些路由, 支持正则表达式
  ignored-patterns:
    - /**/modify/pwd
  # 排除服务
  ignored-services: user-center
  routes:
    eureka-client:
      path: /client1/**
      serviceId: eureka-client

Zuul默认使用 Apache 的 HttpClient 作为HTTP客户端发送请求,超时参数和连接池参数配置如下:

zuul:
  host:
    maxTotalConnections: 200 #连接池最大连接数,仅用于Apache的HttpClient,对于okhttp和restclient无效
    maxPerRouteConnections: 20 #每个路由最大连接数,仅用于Apache的HttpClient,对于okhttp和restclient无效

Zuul完全没有开启重试,如果需要开启重试,添加配置:zuul.retryable=true,并且pom.xml添加如下依赖:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

PS:如果配置了zuul.retryable = true,但没有添加spring-retry到项目中,重试不会开启,反之亦然,必须要两个条件都满足才会开启重试。

PS:重试操作需要服务提供者保证幂等性,相同操作的多次请求需保证结果一致。

Zuul在开启了重试的情况下,重试参数配置如下(替换值):

ribbon:
  MaxAutoRetries: 0 #当前服务器最大重试次数,不包含第1次请求
  MaxAutoRetriesNextServer: 1 #切换服务器最大次数,不包含第1台服务器
  OkToRetryOnAllOperations: false #是否所有操作都要重试,false:只有GET请求才会重试,true:GET、POST、PUT等所有请求都会重试

自定义 Filter

网关最核心的功能当然是集中式路由转发,那么在转发过程中对请求做一些鉴别和限制就是网关提供的高级功能也是必要的功能。

我们假设有这样一个场景,因为服务网关应对的是外部的所有请求,为了避免产生安全隐患,我们需要对请求做一定的限制,比如请求中含有 token 便让请求继续往下走,如果请求不带 token 就直接返回并给出提示。

首先自定义一个 Filter,继承 ZuulFilter 抽象类,在 run () 方法中验证参数是否含有 token ,具体如下:

package com.rickiyang.learn.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

import javax.servlet.http.HttpServletRequest;

/**
 * @author rickiyang
 * @date 2019-12-13
 * @Desc TODO
 */
public class TokenFilter extends ZuulFilter {

    /**
     * 过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。
     * 这里定义为pre,代表会在请求被路由之前执行。
     *
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * filter执行顺序,通过数字指定。
     * 数字越大,优先级越低。
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 判断该过滤器是否需要被执行。这里我们直接返回了true,因此该过滤器对所有请求都会生效。
     * 实际运用中我们可以利用该函数来指定过滤器的有效范围。
     *
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤器的具体逻辑
     *
     * @return
     */
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        String token = request.getParameter("token");
        if (token == null || token.isEmpty()) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("token is empty");
        }
        return null;
    }
}

在上面实现的过滤器代码中,我们通过继承 ZuulFilter 抽象类并重写了下面的四个方法来实现自定义的过滤器。这四个方法分别定义了:

  • filterType():过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为 pre,代表会在请求被路由之前执行。
  • filterOrder():过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行。通过数字指定,数字越大,优先级越低。
  • shouldFilter():判断该过滤器是否需要被执行。这里我们直接返回了 true,因此该过滤器对所有请求都会生效。实际运用中我们可以利用该函数来指定过滤器的有效范围。
  • run():过滤器的具体逻辑。这里我们通过 ctx.setSendZuulResponse(false) 来让 Zuul 过滤该请求,不对其进行路由,然后通过 ctx.setResponseStatusCode(401) 设置了其返回的错误码,当然我们也可以进一步优化我们的返回,比如,通过 ctx.setResponseBody(body) 对返回 body 内容进行编辑等。

在实现了自定义过滤器之后,它并不会直接生效,我们还需要为其创建具体的 Bean 才能启动该过滤器,比如,在应用主类中增加如下内容:

import com.rickiyang.learn.filter.TokenFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@EnableDiscoveryClient
@EnableZuulProxy
@SpringBootApplication
public class ZuulServerApplication {

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

    @Bean
    public TokenFilter tokenFilter() {
        return new TokenFilter();
    }

}

Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是:

  1. pre:在请求被路由之前调用。

  2. routing:将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。

  3. post:在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

  4. error:其他阶段发生错误时执行该过滤器。

整个生命周期可以用下图来表示:

在 Zuul 中提供了一些默认的 Filter:

类型 顺序 过滤器 功能
pre -3 ServletDetectionFilter 标记处理Servlet的类型
pre -2 Servlet30WrapperFilter 包装HttpServletRequest请求
pre -1 FormBodyWrapperFilter 包装请求体
route 1 DebugFilter 标记调试标志
route 5 PreDecorationFilter 处理请求上下文供后续使用
route 10 RibbonRoutingFilter serviceId请求转发
route 100 SimpleHostRoutingFilter url请求转发
route 500 SendForwardFilter forward请求转发
post 0 SendErrorFilter 处理有错误的请求响应
post 1000 SendResponseFilter 处理正常的请求响应

使用 Zuul 进行限流

添加依赖:

<dependency>
    <groupId>com.marcosbarbero.cloud</groupId>
    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
    <version>1.3.2.RELEASE</version>
</dependency>

spring-cloud-zuul-ratelimit是和zuul整合提供分布式限流策略的扩展,只需在yaml中配置几行配置,就可使应用支持限流:

ratelimit:
  enabled: true
  repository: REDIS #使用redis存储,一定要大写!
  policies:
    eureka-client: #针对上面那个服务的限流
      limit: 100 #每秒多少个请求
      quota: 20 #quota 单位时间内允许访问的总时间(统计每次请求的时间综合)
      refreshInterval: 60 #刷新时间窗口的时间,默认值 (秒)
      type:
        - ORIGIN #这里一定要大写,类型说明:URL通过请求路径区分,ORIGIN通过客户端IP地址区分,USER是通过登录用户名进行区分,也包括匿名用户

ratelimit 支持的限流粒度:

  • 服务粒度 (默认配置,当前服务模块的限流控制)
  • 用户粒度 (详细说明,见文末总结)
  • ORIGIN粒度 (用户请求的origin作为粒度控制)
  • 接口粒度 (请求接口的地址作为粒度控制)
  • 以上粒度自由组合,又可以支持多种情况
  • 如果还不够,自定义RateLimitKeyGenerator实现。

支持的存储方式:

  • InMemoryRateLimiter - 使用 ConcurrentHashMap作为数据存储
  • ConsulRateLimiter - 使用 Consul 作为数据存储
  • RedisRateLimiter - 使用 Redis 作为数据存储
  • SpringDataRateLimiter - 使用 数据库 作为数据存储

关于Zuul网关的基本使用本节先讲到这里,下一节继续讲 Zuul 的高阶使用。

おすすめ

転載: www.cnblogs.com/rickiyang/p/12057661.html