首頁 > 軟體

SpringCloud Gateway詳細分析實現負載均衡與熔斷和限流

2022-07-12 14:02:07

環境準備

  • 註冊中心Nacos,也可以其他
  • springboot 2.6.8
  • spring-cloud-dependencies 2021.0.3

1.pom依賴

parent包

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.6.8</version>
</parent>

gateway依賴

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--服務註冊與發現-->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
	<version>2021.0.1.0</version>
</dependency>
<!--遠端服務路由-->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

springcloud版本管理

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>2021.0.3</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

2.yaml設定

spring:
  application:
    name: gatewayservice
  cloud:
    #找對應網段的網路卡 不設定內部服務就走外網
    inetutils:
      preferred-networks: 192.168.0
    nacos:
      discovery:
          #nacos註冊地址
        server-addr: 192.168.0.221:8848
    gateway:
      routes:
      - id: user
          #根據服務名轉發 只需要名稱 不用埠
        uri: lb://userservice
        #ip的形式轉發
#        uri: http://127.0.0.1:7540
        predicates:
        #路由規則
        - Path=/user/**
        filters:
        #1/去掉字首 0/保持原路徑
        - StripPrefix=1
      #跨域設定 
      globalcors:
        cors-configurations:
          '[/**]':
            # 允許攜帶認證資訊
            allowCredentials: true
            # 允許跨域的源(網站域名/ip),設定*為全部
            allowedOriginPatterns: "*"
            # 允許跨域的method, 預設為GET和OPTIONS,設定*為全部
            allowedMethods: "*"
            # 允許跨域請求裡的head欄位,設定*為全部
            allowedHeaders: "*"

#本地靜態路由設定 jar包依賴不一樣
#my-load-balanced-service:
#  ribbon:
#    listOfServers: http://127.0.0.1:7540,http://127.0.0.1:7541
    #輪詢
#    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

3.路由轉發和負載均衡測試

啟動不同埠的user服務,然後通過gateway呼叫

user服務暴露介面

存取地址http://127.0.0.1:7500/user/test

@Value("${server.port}")
String port;
@GetMapping("/test")
public String test() {
    return new Date().getTime() + ":" + port;
}

返回結果輸出

1657261506117:7540
1657261509785:7541
1657261513874:7540
1657261517464:7541

可以正常路由轉發和負載均衡,預設策略是輪詢

4.gateway熔斷實現

熔斷:就是通過在轉發過程中失敗的,從而採取的降級策略。良好的返回提示給前端。

4.1 熔斷程式碼

@Component
public class FallbackHandler implements ErrorWebExceptionHandler {
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        String message = "服務正在維護,請稍後再試!";
        byte[] bytes = String.format("{"code":-1,"message":"%s","data":null}",
                message).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        return exchange.getResponse().writeWith(Flux.just(buffer));
    }
}

本來是想通過Hystrix直接設定重定向的,奈何spring-cloud-starter-netflix-hystrix已經不更新了,沒法相容。直接採用一刀切算了。

4.2 測試

開啟gateway和user服務存取後,然後停掉user。結果如下

{"code":-1,"message":"服務正在維護,請稍後再試!","data":null}

在這裡需要注意的兩個點

  • 如果設定的是服務名,gateway先註冊轉發服務還沒註冊到Nacos時,存取就不會走熔斷,會提示No servers available for service: userservice
  • 如果設定的是http地址,無對應的服務存在時則可以正常走熔斷

5.gateway限流

用的是自帶的令牌桶演演算法,例如總共十個令牌,每秒恢復一個,那麼一秒內最大隻能獲取10個令牌,超過的則直接控制掉返回429 Too Many Requests

5.1 需要整合redis

pom依賴如下

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

5.2 yaml設定

#引入資料庫
redis:
  database: 0
  host: 192.168.0.100
  port: 6379

//限流策略
gateway:
  routes:
  - id: user
    uri: lb://userservice
    predicates:
    - Path=/user/**
    filters:
    #名稱不可修改
    - name: RequestRateLimiter
      args:
          #限流策略名 通過程式碼注入到spring容器中去
        key-resolver: "#{@ipKeyResolver}"
        #令牌桶每秒填充平均速率
        redis‐rate‐limiter.replenishRate: 1
        #令牌桶總容量
        redis‐rate‐limiter.burstCapacity: 2
        # 每次請求獲取的令牌數
        redis-rate-limiter.requestedTokens: 1

上述設定含義:針對ip限流,總令牌數2,沒秒恢復一個,每次獲取一個。也就是說一秒內超過2次則會被限流。

注意上述限流設定缺一不可,不然啟動也不會報錯,也不會生效,重點是轉發也不成功了

5.3 注入到spring容器

//針對ip限流
@Primary
@Bean(value = "ipKeyResolver")
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
//針對路徑限流
//    @Bean(name = "apiKeyResolver")
public KeyResolver apiKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getPath().value());
}

5.4 測試

存取http://127.0.0.1:7500/user/test,一秒記憶體取三次

redis截圖

網頁端截圖

限流生效!

到此這篇關於SpringCloud Gateway詳細分析實現負載均衡與熔斷和限流的文章就介紹到這了,更多相關SpringCloud Gateway負載均衡內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com