微服務看門神-Zuul

三升水發表於2019-05-31

Zuul閘道器和基本應用場景

構建微服務時,常見的問題是為系統的客戶端應用程式提供唯一的閘道器。

事實上,您的服務被拆分為小型微服務應用程式,這些應用程式應該對使用者不可見,否則可能會導致大量的開發/維護工作。還有一些情況,整個生態系統網路流量可能會通過一個可能影響群集效能的點。

為了解決這個問題,Netflix(微服務的一個主要採用者)建立並開源了它的ZuulZuul是Netflix的基於JVM的路由器和伺服器端負載均衡器。後來Spring在Pivotal下已經在其Spring Cloud中對其進行了調整,使我們能夠通過簡單的步驟輕鬆有效地使用zuul。

Zuul是一種邊緣服務,它支援對多個服務請求的代理。它為您的生態系統提供統一的“前門”,允許任何瀏覽器,移動應用程式或其他使用者介面使用來自多個主機的服務。您可以將Zuul與其他Netflix堆疊元件(如Hystrix)整合以實現容錯,使用Eureka進行服務發現,或者使用它來管理整個系統中的路由規則,過濾器和負載平衡。

最重要的是,Spring框架通過Spring boot/cloud很好地適應了所有這些元件。

路由器和過濾器

路由是微服務架構不可或缺的一部分。例如,/可以對映到您的Web應用程式,/api/users對映到使用者服務並/api/shop對映到商店服務。

Netflix使用Zuul進行以下操作:

  • 認證

  • 洞察

  • 壓力測試

  • 金絲雀測試

  • 動態路由

  • 服務遷移

  • 負載脫落

  • 安全

  • 靜態響應處理

  • 主動/主動流量管理

Zuul的規則引擎允許規則和過濾器基本上以任何JVM語言編寫,內建支援Java和Groovy。

 

Zuul元件

Zuul主要有四種型別的過濾器,使我們能夠在任何特定事務的請求處理的不同時間線中攔截流量。我們可以為特定的url模式新增任意數量的過濾器。

  • 前置過濾器 - 在路由請求之前呼叫。

  • 後置過濾器 - 在路由請求後呼叫。

  • 路由過濾器 - 用於路由請求。

  • 錯誤過濾器 - 在處理請求時發生錯誤時呼叫。

使用不同的過濾器在Zuul內部請求處理流程

 

過濾器關鍵概念

關鍵詞備註
型別Type 定義在路由過程中,過濾器被應用的階段
執行順序Execution Order 在同一個Type中,定義過濾器執行的順序
條件Criteria 過濾器被執行必須滿足的條件
動作Action 如果條件滿足,過濾器中將被執行的動作

 

標準過濾器型別

PRE

在請求被路由到源伺服器前要執行的過濾器

適用業務場景

  • 認證

  • 選路由

  • 請求日誌

 

ROUTING

處理將請求傳送到源伺服器的過濾器

 

POST

在響應從源伺服器返回時要被執行的過濾器

  • 對響應增加HTTP 頭

  • 收集統計和度量

  • 將響應以流的方式傳送回客戶端

 

ERROR

上述階段中出現錯誤要執行的過濾器

 

過濾器樣例

public class PreFilter extends ZuulFilter {

// 過濾器型別
 @Override
 public String filterType() {
   return "pre";
}

// 過濾器順序
 @Override
 public int filterOrder() {
   return 1;
}

// 是否加入過濾器流程中
 @Override
 public boolean shouldFilter() {
   return true;
}

// 過濾器執行程式碼
 @Override
 public Object run() {
   RequestContext ctx = RequestContext.getCurrentContext();
   HttpServletRequest request = ctx.getRequest();

   System.out.println("Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString());

   return null;
}

}

 

netflix zuul例項概述

現在讓我們通過使用Zuul建立一個簡單而有意義的生態系統來嘗試一下。我們將建立下面的元件來演示整個事物:

  • 學生微服務 - 基於spring boot啟動的微服務,它只是暴露單個URL以啟用一些搜尋功能。為簡單起見,我們將返回硬編碼值,但在現實世界中,我們可以讓此服務連線資料庫以獲取資料。

  • Zuul閘道器服務

    它基於spring boot啟動,它將基本上攔截學生服務的所有流量並應用一系列請求過濾器然後路由到底層服務,並在響應服務時再次,它將應用一些響應過濾。由於它是一個閘道器,我們可以使用過濾器有效地採取許多有趣和有用的操作。

    閘道器服務的一些共同責任是 -

    • 在閘道器層應用微服務身份驗證和安全性以保護實際服務

    • 我們可以通過使一些日誌記錄在邊緣獲取有意義的資料和統計資料來實現微服務洞察和監控進入生態系統的所有流量,從而為我們提供準確的生產檢視。

    • 動態路由可以根據需要將請求路由到不同的後端群集。

    • 我們可以通過逐漸增加到新叢集的流量來進行執行時壓力測試,以便在許多情況下衡量效能,例如叢集有新的H / W和網路設定,或者部署了新版本的生產程式碼。

    • 我們可以進行動態負載,即為每種型別的請求分配容量,並刪除超出限制的請求。

    • 我們可以應用靜態響應處理,即直接在邊緣構建一些響應,而不是將它們轉發到內部叢集進行處理。

技術棧和執行環境

  • Java 1.8和IntelliJIDEA作為開發環境

  • Spring cloud Zuul作為閘道器代理提供商

  • Spring boot作為應用程式框架

  • Spring Rest用於將微服務暴露為REST

  • Maven作為構建工具

 

建立學生微服務

按照以下步驟開發學生微服務,稍後將通過zuul代理訪問的幾個REST端點。稍後我們將研究zuul部分,現在讓我們先建立學生服務。

建立Spring Boot專案

建立一個Spring boot專案從spring初始化網站,依賴於Web

將專案解壓縮並匯入到IDEA中。在此步驟中,使用命令執行maven構建,mvn clean install以便正確下載所有maven依賴項。

新增幾個REST端點

我們現在只需向此服務新增一些REST端點,以便稍後測試閘道器。為此,我們需要通過新增註釋新增一個REST控制器@RestController。為簡單起見,我們將新增一個模型類Student

完成所有更改後,該類將如下所示。

package com.example.springboostudentservice;

import java.util.Date;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class SpringBootStudentServiceApplication
{
   @RequestMapping(value = "/echoStudentName/{name}")
   public String echoStudentName(@PathVariable(name = "name") String name)
  {
       return "hello <strong style=\"color: red;\">" + name + " </strong> Responsed on : " + new Date();
  }

   @RequestMapping(value = "/getStudentDetails/{name}")
   public Student getStudentDetails(@PathVariable(name = "name") String name)
  {
       return new Student(name, "Pune", "MCA");
  }

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

class Student
{
   String name;
   String address;
   String cls;

   public Student(String name, String address, String cls) {
       super();
       this.name = name;
       this.address = address;
       this.cls = cls;
  }

   public String getName() {
       return name;
  }

   public String getAddress() {
       return address;
  }

   public String getCls() {
       return cls;
  }
}

應用程式配置

spring:
application:
  name: student
server:
port: 8090

這裡我們按屬性給這個服務命名,spring.application.name=student我們也定義了預設埠server.port=8090。我們需要覆蓋預設埠,因為我們將在localhost中執行不同微服務的多個例項。

驗證學生服務

最後使用命令執行maven構建,mvn clean install並通過執行命令將此專案作為spring boot應用程式啟動java -jar target\spring-boot-zuulgatway-student-service-0.0.1-SNAPSHOT.jar。現在,一旦伺服器啟動,轉到瀏覽器並測試端點是否正常工作。

http://localhost:8090/echoStudentName/james

http://localhost:8090/getStudentDetails/james

建立學校微服務

建立過程和學生微服務一樣,但是由於服務之間的功能和差異性,我們需要對介面進行簡單的修改

新增幾個REST斷點

我們現在只需向此服務新增一些REST端點,為此,我們需要通過新增註釋新增一個REST控制器@RestController。為簡單起見,我們將新增一個模型類School

完成所有更改後,該類將如下所示。

@SpringBootApplication
@RestController
public class SpringBootZuulgatewaySchoolServiceApplication {

@RequestMapping(value = "/echoSchoolName/{name}")
public String echoSchoolName(@PathVariable(name = "name") String name)
{
return "hello <strong style=\"color: green;\">" + name + " </strong> Responsed on : " + new Date();
}

@RequestMapping(value = "/getSchoolDetails/{name}")
public School getSchoolDetails(@PathVariable(name = "name") String name)
{
return new School(name, "China", "ZheJiang");
}

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

}

class School
{
String name;
String address;
String cls;

public School(String name, String address, String cls) {
super();
this.name = name;
this.address = address;
this.cls = cls;
}

public String getName() {
return name;
}

public String getAddress() {
return address;
}

public String getCls() {
return cls;
}
}

應用程式配置

現在開啟application.properties檔案並新增這些條目。

 

spring:
application:
  name: school
server:
port: 8100

這裡我們按屬性給這個服務命名,spring.application.name=school我們也定義了預設埠server.port=8100`。我們需要覆蓋預設埠,因為我們將在localhost中執行不同微服務的多個例項。

驗證學校服務

最後使用命令執行maven構建,mvn clean install並通過執行命令將此專案作為spring boot應用程式啟動java -jar target\spring-boot-zuulgatway-school-service-0.0.1-SNAPSHOT.jar。現在,一旦伺服器啟動,轉到瀏覽器並測試端點是否正常工作。

http://localhost:8100/echoSchoolName/學軍中學

http://localhost:8100/getSchoolDetails/學軍中學

現在我們將使用Zuul建立實際的閘道器服務。

建立Zuul閘道器服務

這將是一個基於Spring boot的微服務,但它有一個特殊的功能。它將使用zuul建立一個代表學生服務的API閘道器。稍後我們可以新增任意數量的微服務,如學生服務,學校服務並能夠建立一個強大的微服務生態系統。

建立String Boot專案

spring初始化網站建立一個具有Zuul依賴關係的Spring boot專案。

將專案作為現有maven專案解壓縮並匯入IDEA。在此步驟中,使用命令執行maven構建,mvn clean install以便正確下載所有maven依賴項。

啟用Zuul服務

現在@EnableZuulProxysrc資料夾中的Spring啟動應用程式類中新增註釋。使用此批註,此工件將像Zuul服務代理一樣執行,並將啟用API閘道器層的所有功能,如前所述。然後我們將新增一些過濾器和路由配置。

import com.example.zuuldemo.filters.ErrorFilter;
import com.example.zuuldemo.filters.PostFilter;
import com.example.zuuldemo.filters.PreFilter;
import com.example.zuuldemo.filters.RouteFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableZuulProxy
public class ZuuldemoApplication {

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

   @Bean
   public PreFilter preFilter() {
       return new PreFilter();
  }
   @Bean
   public PostFilter postFilter() {
       return new PostFilter();
  }
   @Bean
   public ErrorFilter errorFilter() {
       return new ErrorFilter();
  }
   @Bean
   public RouteFilter routeFilter() {
       return new RouteFilter();
  }

}

Zuul應用配置

開啟application.yml並在下面新增條目

zuul:
routes:
  student:
    url: http://localhost:8090
  school:
    url: http://localhost:8100
server:
port: 8080

這裡zuul.routes.student.url將路由所有流量以請求/student到實際的學生服務伺服器。zuul.routes.school.url將路由所有流量以請求/school到實際的學校服務伺服器 server.port - 需要覆蓋預設埠,因為我們將在localhost中執行不同微服務的多個例項。

 

新增Zuul過濾器

正如我們已經描述了zuul元件,我們將新增一些過濾器,Zuul支援4種型別的過濾器,即prepostrouteerror。在這裡,我們將建立每種型別的過濾器。

要編寫過濾器,我們基本上需要執行以下步驟:

  • 需要擴充套件 com.netflix.zuul.ZuulFilter

  • 需要重寫filterTypefilterOrdershouldFilterrun方法。這裡的filterType方法只能返回四個String中的任何一個 - pre/post/route/error。降低此值後,過濾器將像特定過濾器一樣執行。

  • run method是根據我們的要求放置濾波器邏輯的地方。

  • 此外,我們可以根據需要新增任意數量的任何特定過濾器,這種情況filterOrder將用於確定該過濾器執行階段該檔案管理器的順序。

前置過濾器程式碼 - 我們將新增以下預過濾器。目前,過濾器除了println用於測試目的之外什麼都不做。但實際上那些功能足以完成前面提到的許多重要方面。

package com.example.springbootzuulgateway.filters;

import javax.servlet.http.HttpServletRequest;

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

public class PreFilter extends ZuulFilter {

@Override
public String filterType() {
  return "pre";
}

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

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

@Override
public Object run() {
  RequestContext ctx = RequestContext.getCurrentContext();
  HttpServletRequest request = ctx.getRequest();

  System.out.println("Request Method : " + request.getMethod() + " Request URL : " + request.getRequestURL().toString());

  return null;
}

}

後置過濾器

package com.example.springbootzuulgateway.filters;

import com.netflix.zuul.ZuulFilter;

public class PostFilter extends ZuulFilter {

  @Override
  public String filterType() {
    return "post";
  }

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

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

  @Override
  public Object run() {
   System.out.println("Inside Response Filter");

    return null;
  }

}

路由過濾器

package com.example.springbootzuulgateway.filters;

import com.netflix.zuul.ZuulFilter;

public class RouteFilter extends ZuulFilter {

  @Override
  public String filterType() {
    return "route";
  }

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

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

  @Override
  public Object run() {
   System.out.println("Inside Route Filter");

    return null;
  }

}

錯誤過濾器

package com.example.springbootzuulgateway.filters;

import com.netflix.zuul.ZuulFilter;

public class ErrorFilter extends ZuulFilter {

  @Override
  public String filterType() {
    return "error";
  }

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

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

  @Override
  public Object run() {
   System.out.println("Inside Route Filter");

    return null;
  }

}

 

5.5。註冊zuul過濾器

建立要自動註冊和啟用的這些過濾器的bean定義。

@Bean
public PreFilter preFilter() {
return new PreFilter();
}
@Bean
public PostFilter postFilter() {
return new PostFilter();
}
@Bean
public ErrorFilter errorFilter() {
return new ErrorFilter();
}
@Bean
public RouteFilter routeFilter() {
return new RouteFilter();
}

 

Netflix zuul示例演示

所以我們啟用了Zuul,新增了所需的配置並開發了過濾器。所以我們可以做基本的測試來理解整個事情。

使用命令執行maven構建,mvn clean install並通過執行命令將此專案作為spring boot應用程式啟動java -jar target\spring-boot-zuulgateway-0.0.1-SNAPSHOT.jar

現在,一旦伺服器啟動,轉到瀏覽器並通過訪問學生服務名稱和學校服務來測試端點是否正常工作,即/student/school

http://localhost:8080/student/echoStudentName/james

http://localhost:8080/school/echoSchoolName/學軍學校

總結

這就是netflix zuul過濾器示例。我建議你自己做,通過代理新增一些更多的底層服務和路由請求,應用不同型別的過濾器並在過濾器中新增真正的邏輯。

連結: https://pan.baidu.com/s/1zpUBTCDNVHO4s8TAIOxKVA 提取碼: 8v7w

請在評論部分將您的問題提交給我。

快樂學習!!

 

相關文章