基於Spring Cloud Zuul搭建網關服務

1. 網關服務所謂何

  在微服務架構風格中,一個大應用被拆分成爲了多個小的服務系統提供出來,這些小的系統他們可以自成體系,也就是說這些小系統可以擁有自己的數據庫,框架甚至語言等,這些小系統通常以提供 RestFul 風格的接口來被 H5, Android, IOS 以及第三方應用程序調用。

  但是在UI上進行展示的時候,我們通常需要在一個界面上展示很多數據,這些數據可能來自於不同的微服務中。如果想通過一個統一的入口來請求不同的服務,那麼給應用專門建立一個網關(Gateway)服務就顯得非常有必要了。下圖展示了一個擁有網關服務的微服務架構設計。
一個簡單的微服務架構設計圖
  微服務中的網關服務同其他服務一樣,被微服務的註冊中心統一發現並管理,網關服務一般負責處理負載均衡、緩存、路由、訪問控制、服務代理、監控、日誌等。本文主要實現網關服務的路由轉發和過濾功能。

2. Zuul來過濾且分發

2.1 NetFlix Zuul

Zuul is the front door for all requests from devices and websites to the backend of the Netflix streaming application. As an edge service application, Zuul is built to enable dynamic routing, monitoring, resiliency, and security.

  以上內容摘自NetFlix Zuul官方Git Wiki。這段話高度概括了Zuul的作用,大概意思是Zuul是所有從客戶端發往服務端的請求的“守門人”,可以提供動態路由、監控、彈性、安全等邊緣服務。

Zuul uses a range of different types of filters that enables us to quickly and nimbly apply functionality to our edge service. These filters help us perform the following functions:

  • Authentication and Security - identifying authentication requirements for each resource and rejecting requests that do not satisfy them.
  • Insights and Monitoring - tracking meaningful data and statistics at the edge in order to give us an accurate view of production.
  • Dynamic Routing - dynamically routing requests to different backend clusters as needed.
  • Stress Testing - gradually increasing the traffic to a cluster in order to gauge performance.
  • Load Shedding - allocating capacity for each type of request and dropping requests that go over the limit.
  • Static Response handling - building some responses directly at the edge instead of forwarding them to an internal cluster
  • Multiregion Resiliency - routing requests across AWS regions in order to diversify our ELB usage and move our edge closer to our members

2.2 Spring Cloud Zuul

Spring Cloud has created an embedded Zuul proxy to ease the development of a common use case where a UI application wants to make proxy calls to one or more back end services. This feature is useful for a user interface to proxy to the back end services it requires, avoiding the need to manage CORS and authentication concerns independently for all the back ends.

  以上內容摘自Spring Cloud官方文檔。大致意思是Spring Cloud內嵌了Zuul以適應一個代理調用多個不同後端服務的通用場景,使得在開發過程中不用關心跨域資源共享和安全認證等細節。

3. 實際動手初體驗

3.1 搭建Eureka微服務框架

  內嵌在Spring Cloud中的Zuul Proxy需要依賴Eureka的服務發現功能,所以萬里長征第一步是搭建Spring Eureka微服務框架。

  1. 新建項目(即project)demo-parent,在它下面新建模塊(即module)demo-eureka-server作爲服務註冊中心、demo-gateway作爲網關服務、demo-web作爲一個普通服務。
    在這裏插入圖片描述
  2. 將demo-eureka-server設置爲註冊中心,並把demo-gateway和demo-web註冊到demo-eureka-server上面。
  • 在demo-eureka-server的pom文件中添加依賴
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
  • 在demo-eureka-server啓動類DemoEurekaServerApplication前面添加@EnableEurekaServer註解表明這個模塊是Eureka服務註冊中心
  • 在demo-eureka-server的application.yml文件中添加配置
server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
      default-zone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
  application:
    name: demo-eureka-server
  • 在demo-gateway和demo-web的pom文件中添加依賴
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • 在demo-gateway和demo-web啓動類前面添加@EnableEurekaClient註解表明這個模塊可以被註冊中心發現
  • 在demo-gateway的application.yml文件中添加配置
server:
  port: 8767

eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka/

spring:
  application:
    name: demo-gateway
  • 在demo-web的application.yml文件中添加與demo-gateway類似的配置,不過要注意區分端口號,設置demo-web的端口號爲8768
  • 此時,分別運行三個模塊的啓動類,可以看到demo-gateway和demo-web已經被註冊到了demo-eureka-server上面
    在這裏插入圖片描述

3.2 配置Gateway服務

  1. 將demo-gateway設置爲網關服務,能夠將請求進行過濾並且分發到不同的服務上
  • 在demo-gateway的pom文件中添加依賴
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • 在demo-gateway啓動類上面添加@EnableZuulProxy註解表明這個模塊是網關服務模塊
  • 在demo-gateway的application.yml文件中添加配置
zuul:
  routes:
    web:
      path: /web/**
      serviceId: demo-web

  這裏採用了手動映射路由的方式,意思是當請求路徑包含“/web”的時候,當前請求會被轉發到demo-web服務上。如果不想手動映射,可以在pom文件引入spring-boot-starter-actuator依賴,再在application.yml添加端點暴露的有關配置(這裏不再詳細說明),瀏覽器訪問http://localhost:8767/actuator/routes就可以看到demo-gateway配置的各服務路徑映射關係。"/web/**":"demo-web"是我們手動配置的映射關係,"/demo-web/**":"demo-web"是自動配置的映射關係,也就是說http://localhost:8767/web/hi和http://localhost:8767/demo-web/hi都會去請求demo-web服務上的hi方法。
在這裏插入圖片描述
2. 實現demo-gateway的過濾功能
  目前demo-gateway已經具備了分發路由的功能,如果想在請求方法之前進行一些驗證,需要繼承ZuulFilter類並重寫有關方法。

@Component
public class CommonAccessPreFilter extends ZuulFilter {

    private static Logger logger = LoggerFactory.getLogger(CommonAccessPreFilter.class);

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

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

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

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        logger.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        String id = request.getParameter("id");
        if (id == null)
            logger.warn("id is null");
        else
            logger.info("id = " + id);
        return null;
    }
}

  filterType方法定義過濾器的類型。Zuul中定義了四種不同類型的過濾器,分別是pre(在請求被路由之前調用)、route(在請求路由時調用)、error(處理請求時發生錯誤時被調用)、post(在route和error之後被調用)。本文使用pre過濾器,即在路由之前做一些驗證。
  filterOrder方法定義過濾器的執行順序,數值越大,優先級越低。
  shouldFilter方法是過濾器的開關,返回true時過濾器纔會生效。
  run方法裏面是具體的過濾邏輯。本文舉例驗證請求參數id是否爲空,針對id是否爲null可以個性化定製不同的邏輯。
  下圖是分別請求http://localhost:8767/web/hi?id=1和http://localhost:8767/web/hi時過濾器打印在控制檯的日誌。
在這裏插入圖片描述在這裏插入圖片描述

4. 腳下足跡永留存

  完整項目源碼已上傳至個人公開GitHub倉庫

發佈了9 篇原創文章 · 獲贊 20 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章