SpringCloud微服務實戰-Zuul-APIGateway(十)

本文轉自:http://blog.csdn.net/qq_22841811/article/details/67637786#準備工做

1 API Gateway

2 Zuul介紹

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。

2.2 Zuul的配置簡述

  • 配置屬性zuul.max.host.connections已被兩個新屬性zuul.host.maxTotalConnections和zuul.host.maxPerRouteConnections替換,默認分別爲200和20。
  • 全部路由的默認Hystrix隔離模式(ExecutionIsolationStrategy)爲SEMAPHORE。 若是首選此隔離模式,則能夠將zuul.ribbonIsolationStrategy更改成THREAD。

2.3 在springcloud中使用zuul

  • Spring Cloud建立了一個嵌入式Zuul代理,以簡化一個很是常見的用例開發,即UI應用程序想要代理對一個或多個後端服務的調用。此功能對於用戶界面代理所需的後端服務很是有用,從而避免了對全部後端獨立管理CORS和身份驗證問題。
  • 要啓用它,使用@EnableZuulProxy註釋一個Spring Boot主類,並將本地調用轉發到相應的服務。按照慣例,ID爲「users」的服務將從位於/ users處的代理(帶有前綴剝離)接收請求。代理使用Ribbon來定位要經過發現轉發的實例,而且全部請求都在hystrix命令中執行,所以故障將顯示在Hystrix指標中,一旦電路打開,代理將不會嘗試聯繫服務。
  • 注意:Zuul啓動器不包括髮現客戶端,所以對於基於服務ID的路由,您須要在類路徑中提供其中一個(例如Eureka是一個選擇)。

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>
  • 啓動類
  • 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/7/25
     */
    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
        public static void main(String[] args) {
            SpringApplication.run(ZuulApplication.class,args);
        }
    }

配置文件:application.ymlhtml

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

3.1 測試

  • 啓動microservice-api-gateway項目。還記得咱們以前訪問經過http://localhost:8000/1去訪問microservice-provider-user服務中id=1的用戶信息嗎?

咱們如今訪問http://localhost:8050/microservice-provider-user/1試試。會驚人地看到:java

{"id":1,"username":"Tom","age":12}

這不正是microservice-provider-user服務中id=1的用戶信息嗎?web

因此咱們能夠總結出規律:訪問正則表達式

將會訪問到 http://GATEWAY:GATEWAY_PORT/想要訪問的Eureka服務id的小寫/**http://想要訪問的Eureka服務id的小寫:該服務端口/**

4 自定義配置Zuul路由

上文咱們已經完成了經過API Gateway去訪問微服務的目的,是經過http://GATEWAY:GATEWAY_PORT/想要訪問的Eureka服務id的小寫/**的形式訪問的,那麼若是咱們想自定義在API Gateway中的路徑呢?譬如想使用http://localhost:8050/user/1就可以將請求路由到http://localhost:8000/1呢?spring

只須要作一點小小的配置便可:apache

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

5 如何忽略某些服務

準備工做

  1. 啓動服務:microservice-discovery-eureka
  2. 啓動服務:microservice-provider-user
  3. 啓動服務:microservice-consumer-movie-ribbon

若是咱們如今只想將microservice-consumer-movie-ribbon服務暴露給外部,microservice-provider-user不想暴露,那麼應該怎麼辦呢?後端

依然只是一點小小的配置便可:api

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
  • 也可以使用ignoredServices:服務名
  • 路由必須有一個「路徑」,能夠指定爲ant樣式模式,因此「/ myusers / 」只匹配一個級別,但「/ myusers / *」分層匹配。
  • 後端的位置能夠被指定爲「serviceId」(對於來自發現的服務)或「url」(對於物理位置),例如。
  • zuul:
      routes:
        users:
          path: /myusers/**
          url: http://example.com/users_service

6 啓動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 

7 使用正則表達規則路由

  • 可使用regexmapper在serviceId和路由之間提供約定。 它使用正則表達式命名的組從serviceId提取變量並將它們注入到路由模式中。
  • regexmapper:用於routepattern轉換爲servicePattern
  • routepattern:路由正則表達式
  • servicePattern:service正則表達式
@Bean
public PatternServiceRouteMapper serviceRouteMapper() {
    return new PatternServiceRouteMapper(
        "(?<name>^.+)-(?<version>v.+$)",
        "${version}/${name}");
}
  • 這意味着serviceId「myusers-v1」將映射到路由「/ v1 / myusers / 」。 接受任何正則表達式,但全部命名組必須同時存在於servicePattern和routePattern中。 若是servicePattern與serviceId不匹配,則使用缺省行爲。 在上面的示例中,serviceId「myusers」將映射到路由「/ myusers / 」(未檢測到任何版本)。此功能默認狀況下處於禁用狀態,僅適用於發現的服務。
zuul:
  ignoredPatterns: /**/admin/**
  routes:
    users: /myusers/**
  • 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文件,由於使用屬性文件將會丟失順序。 例如:若是要使用屬性文件,則舊路徑可能會在用戶路徑前面顯示,致使用戶路徑沒法訪問。服務器

8 zuul.prefix

  • 要向全部映射添加前綴,請將zuul.prefix設置爲一個值,例如/ api。 默認狀況下,在轉發請求以前,從請求中刪除代理前綴(使用zuul.stripPrefix = false關閉此行爲)。
  • prefix和stripPrefix(依賴於prefix的使用)連用影響是全局的
  • path和stripPrefix連用影響是局部的

9 細節知識

9.1 routes

  • 若是使用@EnableZuulProxy與Spring Boot Actuator,您將啓用(默認狀況下)一個額外的端點,經過HTTP做爲/ routes可用。 到此端點的GET將返回映射路由的列表。 POST將強制刷新現有路由(例如,若是服務目錄中有更改)。

9.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

9.3 fallback

  • 在類中定製http返回的屬性
  • package com.clsaa.learn.zuul.fallback;
    
    import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.MediaType;
    import org.springframework.http.client.ClientHttpResponse;
    import org.springframework.stereotype.Component;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    @Component
    public class MyFallbackProvider implements ZuulFallbackProvider {
        @Override
        public String getRoute() {
            //route 如
            return "microservice-provider-user";
        }
    
        @Override
        public ClientHttpResponse fallbackResponse() {
            return new ClientHttpResponse() {
                @Override
                public HttpStatus getStatusCode() throws IOException {
                    return HttpStatus.OK;
                }
    
                @Override
                public int getRawStatusCode() throws IOException {
                    return 200;
                }
    
                @Override
                public String getStatusText() throws IOException {
                    return "OK";
                }
    
                @Override
                public void close() {
    
                }
    
                @Override
                public InputStream getBody() throws IOException {
                    return new ByteArrayInputStream(("fallback"+MyFallbackProvider.this.getRoute()).getBytes());
                }
    
                @Override
                public HttpHeaders getHeaders() {
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.APPLICATION_JSON);
                    return headers;
                }
            };
        }
    }

9.4 使用sidecar支持異構語言

10過濾器

10.1過濾器類型與請求生命週期

  • Zuul大部分功能都是經過過濾器來實現的。Zuul中定義了四種標準過濾器類型,這些過濾器類型對應於請求的典型生命週期。

    1. PRE:這種過濾器在請求被路由以前調用。咱們可利用這種過濾器實現身份驗證、在集羣中選擇請求的微服務、記錄調試信息等。
    2. ROUTING:這種過濾器將請求路由到微服務。這種過濾器用於構建發送給微服務的請求,並使用Apache HttpClient或Netfilx Ribbon請求微服務。
    3. POST:這種過濾器在路由到微服務之後執行。這種過濾器可用來爲響應添加標準的HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。
    4. ERROR:在其餘階段發生錯誤時執行該過濾器。
    5. 除了默認的過濾器類型,Zuul還容許咱們建立自定義的過濾器類型。例如,咱們能夠定製一種STATIC類型的過濾器,直接在Zuul中生成響應,而不將請求轉發到後端的微服務。

image

10.2 編寫zuul過濾器

  • 過濾器類
  • package com.clsaa.learn.zuul;
    
    import com.netflix.zuul.ZuulFilter;
    import com.netflix.zuul.context.RequestContext;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    
    @Component
    public class PreZuulFilter extends ZuulFilter{
        private final static Logger LOGGER = LoggerFactory.getLogger(PreZuulFilter.class);
    
        @Override
        public String filterType() {
            return "pre";
        }
    
        @Override
        public int filterOrder() {
            return 1;//數字越大越靠後
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() {
            HttpServletRequest servletRequest = RequestContext.getCurrentContext().getRequest();
            String host = servletRequest.getRemoteHost();
            PreZuulFilter.LOGGER.info("request host : " + host);
            return null;
        }
    }

10.3 禁用過濾器

479/5000 
Zuul for Spring Cloud在代理和服務器模式下默認啓用了一些ZuulFilter bean。 有關已啓用的可能過濾器,請參閱zuul過濾器包。 若是你想禁用一個,只需設置:

zuul.<SimpleClassName>.<filterType>.disable=true

按照慣例,過濾器以後的包是Zuul過濾器類型。 例如,禁用

org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter set zuul.SendResponseFilter.post.disable = true
相關文章
相關標籤/搜索