
本篇文章為系列文章,未讀前幾集的同學請猛戳這裡:
哈喽沃德先生:Spring Cloud 系列之 Netflix Zuul 服務網關(一)zhuanlan.zhihu.com
哈喽沃德先生:Spring Cloud 系列之 Netflix Zuul 服務網關(二)zhuanlan.zhihu.com
哈喽沃德先生:Spring Cloud 系列之 Netflix Zuul 服務網關(三)zhuanlan.zhihu.com
本篇文章講解 Zuul 和 Sentinel 整合,實作網關限流和容錯以及高可用網關環境搭建。
Zuul 和 Sentinel 整合
https://www.zhihu.com/video/1234209285452181504
Sentinel 支援對 Spring Cloud Gateway、Netflix Zuul 等主流的 API Gateway 進行限流。
官網文檔:
- https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
- https://github.com/alibaba/Sentinel/wiki/網關限流#zuul-1x
網關限流
建立項目
建立
zuul-server-sentinel
項目。
添加依賴
單獨使用添加
sentinel-zuul-adapter
依賴即可。
若想跟 Sentinel Starter 配合使用,需要加上
spring-cloud-alibaba-sentinel-gateway
依賴,同時需要添加
spring-cloud-starter-netflix-zuul
依賴來讓
spring-cloud-alibaba-sentinel-gateway
子產品裡的 Zuul 自動化配置類生效。
同時請将
spring.cloud.sentinel.filter.enabled
配置項置為 false(若在網關流控控制台上看到了 URL 資源,就是此配置項沒有置為 false)。
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>zuul-server-sentinel</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 繼承父依賴 -->
<parent>
<groupId>com.example</groupId>
<artifactId>zuul-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 項目依賴 -->
<dependencies>
<!-- spring cloud netflix zuul 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!-- netflix eureka client 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 單獨使用 -->
<!-- sentinel zuul adapter 依賴 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-zuul-adapter</artifactId>
</dependency>
<!-- 和 Sentinel Starter 配合使用 -->
<!--
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
-->
</dependencies>
</project>
配置檔案
server:
port: 9001 # 端口
spring:
application:
name: zuul-server-sentinel # 應用名稱
cloud:
sentinel:
filter:
enabled: false
# 配置 Eureka Server 注冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 位址注冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設定服務注冊中心位址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
網關服務配置類
配置網關服務過濾器和網關限流規則。
package com.example.config;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter;
import com.netflix.zuul.ZuulFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.Set;
/**
* 網關服務配置類
*/
@Configuration
public class ZuulConfig {
// 底層繼承了 ZuulFilter
@Bean
public ZuulFilter sentinelZuulPreFilter() {
// We can also provider the filter order in the constructor.
return new SentinelZuulPreFilter();
}
// 底層繼承了 ZuulFilter
@Bean
public ZuulFilter sentinelZuulPostFilter() {
return new SentinelZuulPostFilter();
}
// 底層繼承了 ZuulFilter
@Bean
public ZuulFilter sentinelZuulErrorFilter() {
return new SentinelZuulErrorFilter();
}
/**
* Spring 容器初始化的時候執行該方法
*/
@PostConstruct
public void doInit() {
// 加載網關限流規則
initGatewayRules();
}
/**
* 網關限流規則
*/
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
/*
resource:資源名稱,可以是網關中的 route 名稱或者使用者自定義的 API 分組名稱
count:限流門檻值
intervalSec:統計時間視窗,機關是秒,預設是 1 秒
*/
rules.add(new GatewayFlowRule("order-service")
.setCount(3) // 限流門檻值
.setIntervalSec(60)); // 統計時間視窗,機關是秒,預設是 1 秒
// 加載網關限流規則
GatewayRuleManager.loadRules(rules);
}
}
啟動類
ZuulServerSentinelApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
// 開啟 Zuul 注解
@EnableZuulProxy
// 開啟 EurekaClient 注解,目前版本如果配置了 Eureka 注冊中心,預設會開啟該注解
//@EnableEurekaClient
public class ZuulServerSentinelApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServerSentinelApplication.class, args);
}
}
通路
多次通路:http://localhost:9001/order-service/order/1 觸發限流後會傳回固定的提示:
自定義限流處理
發生限流之後的處理流程 :
- 發生限流之後可自定義傳回參數,通過實作
接口,預設的實作是ZuulBlockFallbackProvider
。DefaultBlockFallbackProvider
- 預設的 fallback route 的規則是 route ID 或自定義的 API 分組名稱。
編寫限流處理類
OrderBlockFallbackProvider.java
package com.example.fallback;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 對訂單服務做服務容錯處理
*/
public class OrderBlockFallbackProvider implements ZuulBlockFallbackProvider {
private Logger logger = LoggerFactory.getLogger(OrderBlockFallbackProvider.class);
@Override
public String getRoute() {
return "order-service"; // 服務名稱
}
@Override
public BlockResponse fallbackResponse(String route, Throwable cause) {
logger.error("{} 服務觸發限流", route);
if (cause instanceof BlockException) {
return new BlockResponse(429, "服務通路壓力過大,請稍後再試。", route);
} else {
return new BlockResponse(500, "系統錯誤,請聯系管理者。", route);
}
}
}
将限流處理類注冊至 Zuul 容器
ZuulConfig.java
// Spring 容器初始化的時候執行該方法
@PostConstruct
public void doInit() {
// 注冊 FallbackProvider
ZuulBlockFallbackManager.registerProvider(new OrderBlockFallbackProvider());
// 加載網關限流規則
initGatewayRules();
}
多次通路:http://localhost:9001/order-service/order/1 觸發限流後傳回自定義提示:
高可用網關
業内通常用多少 9 來衡量網站的可用性,例如 QQ 的可用性是 4 個 9,就是說 QQ 能夠保證在一年裡,服務在 99.99% 的時間是可用的,隻有 0.01% 的時間不可用,大約最多 53 分鐘。
對于大多數網站,2 個 9 是基本可用;3 個 9 是叫高可用;4 個 9 是擁有自動恢複能力的高可用。
實作高可用的主要手段是
資料的備援備份和
服務的失效轉移,這兩種手段具體可以怎麼做呢,在網關裡如何展現?主要有以下幾個方向:
- 叢集部署
- 負載均衡
- 健康檢查
- 節點自動重新開機
- 熔斷
- 服務降級
- 接口重試
Nginx + 網關叢集實作高可用網關
下載下傳
官網:http://nginx.org/en/download.html 下載下傳穩定版。為了友善學習,請下載下傳 Windows 版本。
安裝
解壓檔案後直接運作根路徑下的
nginx.exe
檔案即可。
Nginx 預設端口為 80,通路:http://localhost:80/ 看到下圖說明安裝成功。
配置網關叢集
進入 Nginx 的
conf
目錄,打開
nginx.conf
檔案,配置網關叢集:
http {
...
# 網關叢集
upstream gateway {
server 127.0.0.1:9000;
server 127.0.0.1:9001;
}
server {
listen 80;
server_name localhost;
...
# 代理網關叢集,負載均衡調用
location / {
proxy_pass http://gateway;
}
...
}
...
}
通路
啟動兩台網關伺服器
http://localhost:9000/
,
http://localhost:9001/
和相關服務。
通路:http://localhost/product-service/product/1 實作高可用網關。
總結
一個請求過來,首先經過 Nginx 的一層負載,到達網關,然後由網關負載到真實後端,若後端有問題,網關會進行重試通路,多次通路後仍傳回失敗,可以通過熔斷或服務降級立即傳回結果。而且,由于是負載均衡,網關重試時不一定會通路到出錯的後端。
至此 Zuul 服務網關所有的知識點就講解結束了。
大家可以通過
分類
檢視更多關于
Spring Cloud
的文章。
本文采用
知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協定
。
您的
點贊
和
轉發
是對我最大的支援。
掃碼關注
哈喽沃德先生
「文檔 + 視訊」每篇文章都配有專門視訊講解,學習更輕松噢 ~