Spring cloud分佈式系統搭建(六)

六、API網關:Zuul

zuul也叫路由網關,具體啥作用咱目前也不用管,個人喜歡先上手,會用了再去了解它到底是什麼。咱們暫時可以參考controller來理解zuul,簡單來說就類似於路徑帶"/order"訪問訂單服務,帶"/goods"訪問商品服務。

開幹,新建模塊zuul,pom.xml如下:

<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mujio</groupId>
    <artifactId>zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>zuul</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <!-- 引入zuul時使用Hoxton.SR3 -->
<!--        <spring-cloud.version>Greenwich.RC2</spring-cloud.version>-->
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
    </properties>

    <dependencies>
        <!-- 需要eureka依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- zuul依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </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時,會發現依賴報錯,將spring cloud版本換成Hoxton.SR3可解決。

啓動類開啓eureka和zuul的註解:

@EnableDiscoveryClient
@EnableZuulProxy

在這裏插入圖片描述

修改配置文件爲application.yml:

server:
  port: 7100

spring:
  application:
    #指定服務名稱
    name: zuul-server

eureka:
  client:
    #是否註冊到Eureka服務中
    register-with-eureka: true
    #是否從Eureka服務中獲取註冊信息
    fetch-registry: true
    service-url:
      #Eureka客戶端與服務端進行交互的地址
      defaultZone: http://mujio:123456@localhost:7000/eureka/
  instance:
    #把ip地址註冊到Eureka服務中
    prefer-ip-address: true
    ip-address: 127.0.0.1


zuul:
  routes:
    goods-server:
      # 將所有/goods/的路徑映射到goods-server上
      path: /goods/**
      serviceId: goods-server
      strip-prefix: false

啓動,測試http://localhost:7100/goods/1和http://localhost:7100/goods-server/goods/1:在這裏插入圖片描述

我們訪問的是zuul的端口,加上的是商品服務的映射路徑,成功獲取到商品服務的返回值,但是爲什麼這兩個路徑都是正常的呢?大家可以去掉配置文件中的 strip-prefix: false 試試,把path改爲其他值再試試。

在zuul實現路由時,還可以通過繼承ZuulFilter來實現路由前置後置等方法,且看代碼:

package com.mujio.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * 可以通過不同的filter繼承ZuulFilter來實現前置後置等方法
 * FilterConstants.PRE_TYPE請求被路由前調用
 * FilterConstants.POST_TYPE在ROUTE和ERROR後調用
 * FilterConstants.ROUTE_TYPE請求時調用
 * FilterConstants.ERROR_TYPE請求出現錯誤時調用
 */
@Component
public class UserFilter extends ZuulFilter{
    
    // 請求被路由前調用
    @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 {
        HttpServletRequest req = RequestContext.getCurrentContext().getRequest();
        String token = req.getParameter("token");
        if (StringUtils.isEmpty(token)){
            RequestContext.getCurrentContext().setSendZuulResponse(false);//不進行路由
            RequestContext.getCurrentContext().setResponseStatusCode(200);
            RequestContext.getCurrentContext().setResponseBody("{\"error\":\"invalid token\"}");
        }
        return null;
    }
}

重啓,測試http://localhost:7100/goods/1:在這裏插入圖片描述
http://localhost:7100/goods/1?token=1:在這裏插入圖片描述

如上效果,通過zuul實現了token驗證的功能。

解決上一節提到的兩個問題:

  1. eureka服務掛了咋辦?
  2. 啓動多個訂單服務有什麼用?

首先看第一個問題,我們先複製兩份eureka,端口設爲7001、7002。修改三個eureka服務配置文件爲:

eureka:

server:
  port: 7000

spring:
  application:
    name: eureka-server
  security:
    user:
      #認證信息
      name: mujio
      password: 123456

eureka:
  client:
    #是否註冊到Eureka服務中
    register-with-eureka: true
    #是否從Eureka服務中獲取註冊信息---修改爲true
    fetch-registry: true
    service-url:
      #Eureka客戶端與服務端進行交互的地址,加入認證信息---修改爲用","隔開的兩個eureka地址
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@localhost:7001/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@localhost:7002/eureka/

eureka01:

server:
  port: 7001

spring:
  application:
    name: eureka-server
  security:
    user:
      #認證信息
      name: mujio
      password: 123456

eureka:
  client:
    #是否註冊到Eureka服務中
    register-with-eureka: true
    #是否從Eureka服務中獲取註冊信息---修改爲true
    fetch-registry: true
    service-url:
      #Eureka客戶端與服務端進行交互的地址,加入認證信息---修改爲用","隔開的兩個eureka地址
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@localhost:7000/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@localhost:7002/eureka/

eureka02:

server:
  port: 7002

spring:
  application:
    name: eureka-server
  security:
    user:
      #認證信息
      name: mujio
      password: 123456

eureka:
  client:
    #是否註冊到Eureka服務中
    register-with-eureka: true
    #是否從Eureka服務中獲取註冊信息---修改爲true
    fetch-registry: true
    service-url:
      #Eureka客戶端與服務端進行交互的地址,加入認證信息---修改爲用","隔開的兩個eureka地址
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@localhost:7000/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@localhost:7001/eureka/

重啓,測試http://localhost:9000/order/1:
在這裏插入圖片描述

停止eureka,再次訪問;停止eureka01再次訪問;停止eureka02再次訪問。再逐次停止goods-server再次訪問。

可以發現,eureka服務並沒有影響到order服務的運行,但是商品服務的宕機,影響到了order獲取商品的信息,直到所有的eureka和商品服務都宕機了,訂單服務任然能運行,只是獲取不到正確的商品信息。真正實現了訂單服務的高可用。

至此,我們的分佈式系統已經相對完整了,這個時候我們來考慮第二個問題:

2.訂單服務掛了怎麼辦?

其實這個問題我並沒有找到滿意的解答。準確的問題中心並不單單指訂單服務,可以是登陸中心,可以是Zuul網關等等。

假設用戶走進"門店",門店可以通過各種方法保證提供穩定的服務,但是保證門店屹立不倒呢?這個問題還是留着繼續思考吧。

下一節,引入config配置中心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章