微服務(wù)系統(tǒng)中熔斷限流環(huán)節(jié)坟乾,對保護系統(tǒng)的穩(wěn)定性起到了很大的作用径缅,作為網(wǎng)關(guān),Spring Cloud Gateway也提供了很好的支持菠赚。先來理解下熔斷限流概念:
熔斷降級
:在分布式系統(tǒng)中驳阎,網(wǎng)關(guān)作為流量的入口抗愁,大量請求進(jìn)入網(wǎng)關(guān)馁蒂,向后端遠(yuǎn)程系統(tǒng)或服務(wù)發(fā)起調(diào)用,后端服務(wù)不可避免的會產(chǎn)生調(diào)用失斨╇纭(超時或者異常)沫屡,失敗時不能讓請求堆積在網(wǎng)關(guān)上,需要快速失敗并返回回去撮珠,這就需要在網(wǎng)關(guān)上做熔斷沮脖、降級操作。限流
:網(wǎng)關(guān)上有大量請求芯急,對指定服務(wù)進(jìn)行限流勺届,可以很大程度上提高服務(wù)的可用性與穩(wěn)定性,限流的目的是通過對并發(fā)訪問/請求進(jìn)行限速娶耍,或?qū)σ粋€時間窗口內(nèi)的請求進(jìn)行限速來保護系統(tǒng)免姿。一旦達(dá)到限制速率則可以拒絕服務(wù)、排隊或等待榕酒、降級胚膊。
下文就網(wǎng)關(guān)如何進(jìn)行超時熔斷、異常熔斷和訪問限流進(jìn)行示例說明想鹰。示例包含兩個模塊項目紊婉,一個為網(wǎng)關(guān)項目gateway
,一個為下游業(yè)務(wù)項目downstream
辑舷。
超時異常熔斷
構(gòu)建網(wǎng)關(guān)目:
pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>${spring.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 8089
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
routes:
- id: service_customer
#下游服務(wù)地址
uri: http://127.0.0.1:8083/
order: 0
#網(wǎng)關(guān)斷言匹配
predicates:
- Path=/gateway/**
filters:
#熔斷過濾器
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/defaultfallback
- StripPrefix=1
#熔斷器配置
hystrix:
command:
default:
execution:
isolation:
strategy: SEMAPHORE
thread:
timeoutInMilliseconds: 3000
shareSecurityContext: true
#網(wǎng)關(guān)日志輸出
logging:
level:
org.springframework.cloud.gateway: TRACE
org.springframework.http.server.reactive: DEBUG
org.springframework.web.reactive: DEBUG
reactor.ipc.netty: DEBUG
以上配置的意思是:
- 網(wǎng)關(guān)服務(wù)以端口8089暴露
- 訪問
http://127.0.0.1:8089/gateway/
開頭的請求喻犁,將都被路由到下游http://127.0.0.1:8083/
下,且gateway
部分將被移除(StripPrefix=1
)何缓。比如http://127.0.0.1:8089/gateway/test ----> http://127.0.0.1:8083/test - 超時異常熔斷采用hystrix的SEMAPHORE策略肢础,超時時間為3秒,如果下游服務(wù)不可達(dá)(異常)歌殃,將由fallbackcmd處理乔妈,路由到本地http://127.0.0.1:8089/defaultfallback 處理蝙云。
構(gòu)建defaultfallback處理器
@RestController
public class SelfHystrixController {
@RequestMapping("/defaultfallback")
public Map<String,String> defaultfallback(){
System.out.println("請求被熔斷.");
Map<String,String> map = new HashMap<>();
map.put("Code","fail");
map.put("Message","服務(wù)異常");
map.put("result","");
return map;
}
}
先不構(gòu)建下游服務(wù)氓皱,直接運行網(wǎng)關(guān),訪問地址http://127.0.0.1:8089/gateway/test
勃刨,出現(xiàn)如下情況:
構(gòu)建下游服務(wù)項目波材,該項目為簡單的spring boot web項目,具體配置不詳述身隐,添加服務(wù)類:
@RestController
public class TestController {
@RequestMapping("/timeout")
public String timeout(String name) {
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
return "timeout params:" + name;
}
}
可以發(fā)現(xiàn)廷区,網(wǎng)關(guān)熔斷策略是超時3秒就熔斷,而下游服務(wù)需要用時5秒+贾铝。運行下游服務(wù)隙轻,繼續(xù)在瀏覽器內(nèi)訪問地址http://127.0.0.1:8089/gateway/timeout
,如果正確配置埠帕,3秒后,仍將顯示以上結(jié)果:
--------------------------------------小總結(jié)------------------------------------------------
可見玖绿,通過簡單配置敛瓷,在服務(wù)不可達(dá)和下游服務(wù)超時的情況下,Spring Cloud Gateway成功進(jìn)行了熔斷斑匪。
限流
擴充網(wǎng)關(guān)項目
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
添加基于redis令牌桶機制的限流支持
當(dāng)然網(wǎng)關(guān)還需要配置redis地址呐籽,以本地redis為例:
server:
redis:
host: localhost
添加限流鍵參數(shù)
通過該鍵來判斷服務(wù)用戶身份,比如一個客戶端IP為一個用戶蚀瘸,一個usrid為一個用戶狡蝶,添加配置類:
@Configuration
public class RateLimiterConfig {
@Bean(value = "remoteAddKeyResolver")
public KeyResolver remoteAddKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
添加限流策略
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
routes:
- id: service_customer
#下游服務(wù)地址
uri: http://127.0.0.1:8083/
order: 0
#網(wǎng)關(guān)斷言匹配
predicates:
- Path=/gateway/**
filters:
#熔斷過濾器
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/defaultfallback
- StripPrefix=1
#限流過濾器
- name: RequestRateLimiter
args:
key-resolver: '#{@remoteAddKeyResolver}'
# 每秒最大訪問次數(shù)(放令牌桶的速率)
redis-rate-limiter.replenishRate: 10
# 令牌桶最大容量(令牌桶的大小)
redis-rate-limiter.burstCapacity: 10
主要是兩個參數(shù)redis-rate-limiter.replenishRate: 10
贮勃、redis-rate-limiter.burstCapacity: 10
,前者控制往令牌桶丟令牌的速率贪惹,后者標(biāo)識令牌桶的最大容量。
具體令牌桶算法可以參考下圖:
算法描述
假如用戶配置的平均發(fā)送速率為r衙猪,則每隔1/r秒一個令牌被加入到桶中
假設(shè)桶中最多可以存放b個令牌馍乙。如果令牌到達(dá)時令牌桶已經(jīng)滿了,那么這個令牌會被丟棄
當(dāng)流量以速率v進(jìn)入垫释,從桶中以速率v取令牌丝格,拿到令牌的流量通過,拿不到令牌流量不通過棵譬,執(zhí)行熔斷邏輯
當(dāng)然這個只是概念显蝌,具體可以參考令牌桶算法
添加下游正常方法
@RequestMapping("/hello")
public String hello(String name) {
return "hi " + name;
}
Jmeter壓測
修改限流參數(shù):
# 每秒最大訪問次數(shù)(放令牌桶的速率)
redis-rate-limiter.replenishRate: 2
# 令牌桶最大容量(令牌桶的大小)
redis-rate-limiter.burstCapacity: 10
配置Jmeter參數(shù):
測試結(jié)果
200次請求订咸,成功返回的大概有14次曼尊,異常請求的返回值為:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Remaining: 0
X-RateLimit-Burst-Capacity: 10
X-RateLimit-Replenish-Rate: 2
content-length: 0
修改限流參數(shù),重新測試
# 每秒最大訪問次數(shù)(放令牌桶的速率)
redis-rate-limiter.replenishRate: 20
# 令牌桶最大容量(令牌桶的大性嗳隆)
redis-rate-limiter.burstCapacity: 20
查看匯總結(jié)果骆撇,發(fā)現(xiàn)正常返回結(jié)果的數(shù)量明顯變多(100%-26.5%=84%
)
限流功能正常!
-------------------------------------------慣例給源碼---------------------------------------------
https://gitee.com/BeautifulHao/Spring-Cloud-Gateway-Demo.git