Spring Cloud Gateway 整合阿里 Sentinel 網(wǎng)關(guān)限流實(shí)戰(zhàn)
前一篇文章介紹了Spring Cloud Gateway的一些基礎(chǔ)知識(shí)點(diǎn),今天陳某就來(lái)嘮一嘮網(wǎng)關(guān)層面如何做限流?
文章目錄如下:
網(wǎng)關(guān)如何限流?
Spring Cloud Gateway本身自帶的限流實(shí)現(xiàn),過(guò)濾器是RequestRateLimiterGatewayFilterFactory,不過(guò)這種上不了臺(tái)面的就不再介紹了,有興趣的可以實(shí)現(xiàn)下。
今天的重點(diǎn)是集成阿里的Sentinel實(shí)現(xiàn)網(wǎng)關(guān)限流,sentinel有不懂的可以看陳某的文章:阿里限流神器Sentinel奪命連環(huán) 17 問(wèn)?
從1.6.0版本開(kāi)始,Sentinel提供了SpringCloud Gateway的適配模塊,可以提供兩種資源維度的限流:
- route維度:即在配置文件中配置的路由條目,資源名為對(duì)應(yīng)的routeId,這種屬于粗粒度的限流,一般是對(duì)某個(gè)微服務(wù)進(jìn)行限流。
 - 自定義API維度:用戶可以利用Sentinel提供的API來(lái)自定義一些API分組,這種屬于細(xì)粒度的限流,針對(duì)某一類(lèi)的uri進(jìn)行匹配限流,可以跨多個(gè)微服務(wù)。
 
sentinel官方文檔:https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
Spring Cloud Gateway集成Sentinel實(shí)現(xiàn)很簡(jiǎn)單,這就是阿里的魅力,提供簡(jiǎn)單、易操作的工具,讓程序員專(zhuān)注于業(yè)務(wù)。
新建項(xiàng)目
新建一個(gè)gateway-sentinel9026模塊,添加如下依賴:
- <!--nacos注冊(cè)中心-->
 - <dependency>
 - <groupId>com.alibaba.cloud</groupId>
 - <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 - </dependency>
 - <!--spring cloud gateway-->
 - <dependency>
 - <groupId>org.springframework.cloud</groupId>
 - <artifactId>spring-cloud-starter-gateway</artifactId>
 - </dependency>
 - <!-- spring cloud gateway整合sentinel的依賴-->
 - <dependency>
 - <groupId>com.alibaba.cloud</groupId>
 - <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
 - </dependency>
 - <!-- sentinel的依賴-->
 - <dependency>
 - <groupId>com.alibaba.cloud</groupId>
 - <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
 - </dependency>
 
注意:這依然是一個(gè)網(wǎng)關(guān)服務(wù),不要添加WEB的依賴
配置文件
配置文件中主要指定以下三種配置:
- nacos的地址
 - sentinel控制臺(tái)的地址
 - 網(wǎng)關(guān)路由的配置
 
配置如下:
- spring:
 - cloud:
 - ## 整合sentinel,配置sentinel控制臺(tái)的地址
 - sentinel:
 - transport:
 - ## 指定控制臺(tái)的地址,默認(rèn)端口8080
 - dashboard: localhost:8080
 - nacos:
 - ## 注冊(cè)中心配置
 - discovery:
 - # nacos的服務(wù)地址,nacos-server中IP地址:端口號(hào)
 - server-addr: 127.0.0.1:8848
 - gateway:
 - ## 路由
 - routes:
 - ## id只要唯一即可,名稱任意
 - - id: gateway-provider
 - uri: lb://gateway-provider
 - ## 配置斷言
 - predicates:
 - ## Path Route Predicate Factory斷言,滿足/gateway/provider/**這個(gè)請(qǐng)求路徑的都會(huì)被路由到http://localhost:9024這個(gè)uri中
 - - Path=/gateway/provider/**
 
上述配置中設(shè)置了一個(gè)路由gateway-provider,只要請(qǐng)求路徑滿足/gateway/provider/**都會(huì)被路由到gateway-provider這個(gè)服務(wù)中。
限流配置
經(jīng)過(guò)上述兩個(gè)步驟其實(shí)已經(jīng)整合好了Sentinel,此時(shí)訪問(wèn)一下接口:http://localhost:9026/gateway/provider/port
然后在sentinel控制臺(tái)可以看到已經(jīng)被監(jiān)控了,監(jiān)控的路由是gateway-provider,如下圖:
此時(shí)我們可以為其新增一個(gè)route維度的限流,如下圖:
上圖中對(duì)gateway-provider這個(gè)路由做出了限流,QPS閾值為1。
此時(shí)快速訪問(wèn):http://localhost:9026/gateway/provider/port,看到已經(jīng)被限流了,如下圖:
以上route維度的限流已經(jīng)配置成功,小伙伴可以自己照著上述步驟嘗試一下。
API分組限流也很簡(jiǎn)單,首先需要定義一個(gè)分組,API管理-> 新增API分組,如下圖:
匹配模式選擇了精確匹配(還有前綴匹配,正則匹配),因此只有這個(gè)uri:http://xxxx/gateway/provider/port會(huì)被限流。
第二步需要對(duì)這個(gè)分組添加流控規(guī)則,流控規(guī)則->新增網(wǎng)關(guān)流控,如下圖:
API名稱那里選擇對(duì)應(yīng)的分組即可,新增之后,限流規(guī)則就生效了。
陳某不再測(cè)試了,小伙伴自己動(dòng)手測(cè)試一下吧...............
陳某這里只是簡(jiǎn)單的配置一下,至于限流規(guī)則持久化一些內(nèi)容請(qǐng)看陳某的Sentinel文章,這里就不再過(guò)多的介紹了。
如何自定義限流異常信息?
從上面的演示中可以看到默認(rèn)的異常返回信息是:"Block.........",這種肯定是客戶端不能接受的,因此需要定制自己的異常返回信息。
下面介紹兩種不同的方式定制異常返回信息,開(kāi)發(fā)中自己選擇其中一種。
直接配置文件中定制
開(kāi)發(fā)者可以直接在配置文件中直接修改返回信息,配置如下:
- spring:
 - cloud:
 - ## 整合sentinel,配置sentinel控制臺(tái)的地址
 - sentinel:
 - #配置限流之后,響應(yīng)內(nèi)容
 - scg:
 - fallback:
 - ## 兩種模式,一種是response返回文字提示信息,
 - ## 一種是redirect,重定向跳轉(zhuǎn),需要同時(shí)配置redirect(跳轉(zhuǎn)的uri)
 - mode: response
 - ## 響應(yīng)的狀態(tài)
 - response-status: 200
 - ## 響應(yīng)體
 - response-body: '{"code": 200,"message": "請(qǐng)求失敗,稍后重試!"}'
 
上述配置中mode配置的是response,一旦被限流了,將會(huì)返回JSON串。
- {
 - "code": 200,
 - "message": "請(qǐng)求失敗,稍后重試!"
 - }
 
重定向的配置如下:
- spring:
 - cloud:
 - ## 整合sentinel,配置sentinel控制臺(tái)的地址
 - sentinel:
 - #配置限流之后,響應(yīng)內(nèi)容
 - scg:
 - fallback:
 - ## 兩種模式,一種是response返回文字提示信息,一種是redirect,重定向跳轉(zhuǎn),需要同時(shí)配置redirect(跳轉(zhuǎn)的uri)
 - mode: redirect
 - ## 跳轉(zhuǎn)的URL
 - redirect: http://www.baidu.com
 
一旦被限流,將會(huì)直接跳轉(zhuǎn)到:http://www.baidu.com
編碼定制
這種就不太靈活了,通過(guò)硬編碼的方式,完整代碼如下:
- @Configuration
 - public class GatewayConfig {
 - /**
 - * 自定義限流處理器
 - */
 - @PostConstruct
 - public void initBlockHandlers() {
 - BlockRequestHandler blockHandler = (serverWebExchange, throwable) -> {
 - Map map = new HashMap();
 - map.put("code",200);
 - map.put("message","請(qǐng)求失敗,稍后重試!");
 - return ServerResponse.status(HttpStatus.OK)
 - .contentType(MediaType.APPLICATION_JSON_UTF8)
 - .body(BodyInserters.fromObject(map));
 - };
 - GatewayCallbackManager.setBlockHandler(blockHandler);
 - }
 - }
 
兩種方式介紹完了,根據(jù)業(yè)務(wù)需求自己選擇適合的方式,當(dāng)然陳某更喜歡第一種,理由:約定>配置>編碼。
網(wǎng)關(guān)限流了,服務(wù)就安全了嗎?
很多人認(rèn)為只要網(wǎng)關(guān)層面做了限流,躲在身后的服務(wù)就可以高枕無(wú)憂了,你是不是也有這種想法?
很顯然這種想法是錯(cuò)誤的,復(fù)雜的微服務(wù)架構(gòu)一個(gè)獨(dú)立服務(wù)不僅僅被一方調(diào)用,往往是多方調(diào)用,如下圖:
商品服務(wù)不僅僅被網(wǎng)關(guān)層調(diào)用,還被內(nèi)部訂單服務(wù)調(diào)用,這時(shí)候僅僅在網(wǎng)關(guān)層限流,那么商品服務(wù)還安全嗎?
一旦大量的請(qǐng)求訂單服務(wù),比如大促秒殺,商品服務(wù)不做限流會(huì)被瞬間擊垮。
因此需要根據(jù)公司業(yè)務(wù)場(chǎng)景對(duì)自己負(fù)責(zé)的服務(wù)也要進(jìn)行限流兜底,最常見(jiàn)的方案:網(wǎng)關(guān)層集群限流+內(nèi)部服務(wù)的單機(jī)限流兜底,這樣才能保證不被流量沖垮。
總結(jié)
文章介紹了Spring Cloud Gateway整合Sentinel對(duì)網(wǎng)關(guān)層進(jìn)行限流,以及關(guān)于限流的一些思考。






















 
 
 

















 
 
 
 