亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

Spring cloud 限流的多種方式

瀏覽:2日期:2023-07-12 10:55:25
目錄一、實(shí)戰(zhàn)基于 Spring cloud Gateway 的限流二、基于阿里開源限流神器:Sentinel

在頻繁的網(wǎng)絡(luò)請求時(shí),服務(wù)有時(shí)候也會(huì)受到很大的壓力,尤其是那種網(wǎng)絡(luò)攻擊,非法的。這樣的情形有時(shí)候需要作一些限制。例如:限制對方的請求,這種限制可以有幾個(gè)依據(jù):請求IP、用戶唯一標(biāo)識(shí)、請求的接口地址等等。

當(dāng)前限流的方式也很多:Spring cloud 中在網(wǎng)關(guān)本身自帶限流的一些功能,基于 redis 來做的。同時(shí),阿里也開源了一款:限流神器 Sentinel。今天我們主要圍繞這兩塊來實(shí)戰(zhàn)微服務(wù)的限流機(jī)制。

首先講 Spring cloud 原生的限流功能,因?yàn)橄蘖骺梢允菍γ總€(gè)服務(wù)進(jìn)行限流,也可以對于網(wǎng)關(guān)統(tǒng)一作限流處理。

一、實(shí)戰(zhàn)基于 Spring cloud Gateway 的限流

pom.xml引入依賴:

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

其基礎(chǔ)是基于redis,所以:

spring: application: name: gateway-service redis: #redis相關(guān)配置 database: 8 host: 10.12.15.5 port: 6379 password: 123456 #有密碼時(shí)設(shè)置 jedis: pool:max-active: 8max-idle: 8min-idle: 0 timeout: 10000ms

接下來需要注入限流策略的 bean:

@Primary @Bean(value = 'ipKeyResolver') KeyResolver ipKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); //return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()); //return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()); } @Bean(value = 'apiKeyResolver') KeyResolver apiKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getPath().value()); } @Bean(value = 'userKeyResolver') KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst('userId')); }

這里引入ipKeyResolver、apiKeyResolver、userKeyResolver三種策略,可以利用注解 @Primary 來決定其中一個(gè)被使用。

注入bean后,需要在配置中備用:

spring: application: name: gateway-service redis: #redis相關(guān)配置 database: 8 host: 10.12.15.5 port: 6379 password: 123456 #有密碼時(shí)設(shè)置 jedis: pool:max-active: 8max-idle: 8min-idle: 0 timeout: 10000ms

后面是限流的主要配置:

spring cloud: gateway: routes: #路由配置:參數(shù)為一個(gè)List - id: cas-server #唯一標(biāo)識(shí)uri: lb://cas-server-service #轉(zhuǎn)發(fā)的地址,寫服務(wù)名稱order: -1predicates:- Path=/cas-server/** #判斷匹配條件,即地址帶有/ribbon/**的請求,會(huì)轉(zhuǎn)發(fā)至lb:cas-server-servicefilters:- StripPrefix=1 #去掉Path前綴,參數(shù)為1代表去掉/ribbon- name: RequestRateLimiter #基于redis的Gateway的自身限流 args: redis-rate-limiter.replenishRate: 1 # 允許用戶每秒處理多少個(gè)請求 redis-rate-limiter.burstCapacity: 3 # 令牌桶的容量,允許在一秒鐘內(nèi)完成的最大請求數(shù) key-resolver: '#{@ipKeyResolver}' #SPEL表達(dá)式取的對應(yīng)的bean - id: admin-weburi: lb://admin-web-serviceorder: -1predicates:- Path=/admin-web/**filters:- StripPrefix=1- name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 1 # 允許用戶每秒處理多少個(gè)請求 redis-rate-limiter.burstCapacity: 3 # 令牌桶的容量,允許在一秒鐘內(nèi)完成的最大請求數(shù) key-resolver: '#{@ipKeyResolver}' #SPEL表達(dá)式取的對應(yīng)的bean

這里是在原有的路由基礎(chǔ)上加入 RequestRateLimiter限流過濾器,包括三個(gè)參數(shù):

- name: RequestRateLimiter #基于redis的Gateway的自身限流 args: redis-rate-limiter.replenishRate: 3 #允許用戶每秒處理多少個(gè)請求 redis-rate-limiter.burstCapacity: 5 #令牌桶的容量,允許在一秒鐘內(nèi)完成的最大請求數(shù) key-resolver: '#{@ipKeyResolver}' #SPEL表達(dá)式取的對應(yīng)的bean 其中 replenishRate,其含義表示允許每秒處理請求數(shù); burstCapacity 表示允許在一秒內(nèi)處理的最大請求數(shù); key-resolver 這里采用請求 IP 限流,利用SPEL 表達(dá)式取對應(yīng)的 bean

寫一個(gè)小腳本來壓測一下:

for i in $(seq 1 30000); do echo $(expr $i * 3 + 1);curl -i -H 'Accept: application/json' -H 'Authorization:bearer b064d95b-af3f-4053-a980-377c63ab3413' -X GET http://10.10.15.5:5556/order-service/api/order/getUserInfo;donefor i in $(seq 1 30000); do echo $(expr $i * 3 + 1);curl -i -H 'Accept: application/json' -H 'Authorization:bearer b064d95b-af3f-4053-a980-377c63ab3413' -X GET http://10.10.15.5:5556/admin-web/api/user/getCurrentUser;done

上面兩個(gè)腳本分別對2個(gè)服務(wù)進(jìn)行壓測,打印結(jié)果:

{'message':{'status':200,'code':0,'message':'success'},'data':'{'message':{'status':200,'code':0,'message':'get user success'},'data':{'id':23,'isAdmin':1,'userId':'fbb18810-e980-428c-932f-848f3b9e7c84','userType':'super_admin','username':'admin','realName':'super_admin','password':'$2a$10$89AqlYKlnsTpNmWcCMvgluRFQ/6MLK1k/nkBpz.Lw6Exh.WMQFH6W','phone':null,'email':null,'createBy':'admin','createTime':1573119753172,'updateBy':'admin','updateTime':1573119753172,'loginTime':null,'expireTime':null,'remarks':'super_admin','delFlag':0,'loginType':null}}'}ex

在用測試工具Jmeter在同一秒內(nèi)多次請求后:

HTTP/1.1 429 Too Many RequestsX-RateLimit-Remaining: 0X-RateLimit-Burst-Capacity: 3X-RateLimit-Replenish-Rate: 1content-length: 0expr: syntax errorHTTP/1.1 429 Too Many RequestsX-RateLimit-Remaining: 0X-RateLimit-Burst-Capacity: 3X-RateLimit-Replenish-Rate: 1content-length: 0expr: syntax error

從上面可以看到,執(zhí)行后,會(huì)出現(xiàn)調(diào)用失敗的情況,狀態(tài)變?yōu)?29 (Too Many Requests) 。

二、基于阿里開源限流神器:Sentinel

首先引入依賴:

<!--基于 阿里的sentinel作限流 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>

在配置文件 application.yaml 文件中配置,需要新增2個(gè)配置:

spring: application: name: admin-web cloud: kubernetes: discovery:all-namespaces: true sentinel: eager: true #取消Sentinel控制臺(tái)的懶加載 transport:dashboard: 10.12.15.2:8080 #sentinel的Dashboard地址port: 8719 #是sentinel應(yīng)用端和控制臺(tái)通信端口heartbeat-interval-ms: 500 #心跳時(shí)間 scg:fallback: #scg.fallback為sentinel限流后的響應(yīng)配置 mode: response response-status: 455 response-body: 已被限流

其中,這里面配置了一個(gè)服務(wù):spring.cloud.sentinel.transport.dashboard,配置的是 sentinel 的 Dashboard 地址。同時(shí) spring.cloud.sentinel.transport.port 這個(gè)端口配置會(huì)在應(yīng)用對應(yīng)的機(jī)器上啟動(dòng)一個(gè)Http Server,該 Server 會(huì)與 Sentinel 控制臺(tái)做交互。

Sentinel 默認(rèn)為所有的 HTTP 服務(wù)提供限流埋點(diǎn),上面配置完成后自動(dòng)完成所有埋點(diǎn),只需要控制配置限流規(guī)則即可。這里我們講下通過注解來給指定接口函數(shù)加上限流埋點(diǎn),寫一個(gè)RestController,在接口函數(shù)上加上注解

@SentinelResource:@GetMapping(value = '/getToken')@SentinelResource('getToken')public Response<Object> getToken(Authentication authentication){ //Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); authentication.getCredentials(); OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails(); String token = details.getTokenValue(); return Response.ok(200, 0, 'get token success', token);}

以上代碼部分完成了,接下來先安裝SentinelDashBoard,Sentinel DashBoard下載地址:github.com/alibaba/Sentinel/releases。

下載完成后,命令啟動(dòng):

java -jar sentinel-dashboard-1.6.2.jar

默認(rèn)啟動(dòng)端口為8080,訪問 IP:8080,就可以顯示 Sentinel 的登錄界面,用戶名與密碼均為sentinel。登錄 Dashboard 成功后,多次訪問接口'/getToken',可以在 Dashboard 看到相應(yīng)數(shù)據(jù),這里不展示了。接下來可以設(shè)置接口的限流功能,在 “+流控” 按鈕點(diǎn)擊打開設(shè)置界面,設(shè)置閾值類型為 qps,單機(jī)閾值為5。

瀏覽器重復(fù)請求 http://10.10.15.5:5556/admin-web/api/user/getToken 如果超過閥值就會(huì)出現(xiàn)如下界面信息:Blocked by Sentinel (flow limiting)

此時(shí),就看到Sentinel 限流起作用了,可以加上 spring.cloud.sentinel.scg.fallback 為sentinel 限流后的響應(yīng)配置,亦可自定義限流異常信息:

@GetMapping(value = '/getToken')@SentinelResource(value = 'getToken', blockHandler = 'handleSentinelException', blockHandlerClass = {MySentinelException.class}))public Response<Object> getToken(Authentication authentication){ //Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); authentication.getCredentials(); OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)authentication.getDetails(); String token = details.getTokenValue(); return Response.ok(200, 0, 'get token success', token);}public class MySentinelException { public static Response<Object> handleSentinelException(BlockException e) {Map<String,Object> map=new HashMap<>();logger.info('Oops: ' + ex.getClass().getCanonicalName());return Response.ok(200, -8, '通過注解 @SentinelResource 配置限流埋點(diǎn)并自定義限流后的處理邏輯', null); }}

這里講下注解 @SentinelResource 包含以下屬性:

value:資源名稱,必需項(xiàng); entryType:入口類型,可選項(xiàng)(默認(rèn)為 EntryType.OUT); blockHandler:blockHandlerClass中對應(yīng)的異常處理方法名,參數(shù)類型和返回值必須和原方法一致; blockHandlerClass:自定義限流邏輯處理類

Sentinel 限流邏輯處理完畢了,但每次服務(wù)重啟后,之前配置的限流規(guī)則就會(huì)被清空。因?yàn)槭莾?nèi)存形式的規(guī)則對象。所以下面就講下用 Sentinel 的一個(gè)特性 ReadableDataSource 獲取文件、數(shù)據(jù)庫或者配置中心設(shè)置限流規(guī)則,目前支持 Apollo、Nacos、ZK 配置來管理。

首先回憶一下,一條限流規(guī)則主要由下面幾個(gè)因素組成:

resource:資源名,即限流規(guī)則的作用對象,即為注解 @SentinelResource 的value; count:限流閾值;grade:限流閾值類型(QPS 或并發(fā)線程數(shù)); limitApp:流控針對的調(diào)用來源,若為 default 則不區(qū)分調(diào)用來源; strategy:基于調(diào)用關(guān)系的限流策略; controlBehavior:流量控制效果(直接拒絕、排隊(duì)等待、勻速器模式)

理解了意思,接下來通過文件來配置:

#通過文件讀取限流規(guī)則spring.cloud.sentinel.datasource.ds1.file.file=classpath:flowrule.jsonspring.cloud.sentinel.datasource.ds1.file.data-type=jsonspring.cloud.sentinel.datasource.ds1.file.rule-type=flow

在resources新建一個(gè)文件,比如 flowrule.json 添加限流規(guī)則:

[ { 'resource': 'getToken', 'count': 1, 'controlBehavior': 0, 'grade': 1, 'limitApp': 'default', 'strategy': 0 }, { 'resource': 'resource', 'count': 1, 'controlBehavior': 0, 'grade': 1, 'limitApp': 'default', 'strategy': 0 }]

重新啟動(dòng)項(xiàng)目,出現(xiàn)如下日志說明成功:

DataSource ds1-sentinel-file-datasource start to loadConfigDataSource ds1-sentinel-file-datasource load 2 FlowRule

如果采用 Nacos 作為配置獲取限流規(guī)則,可在文件中加如下配置:

spring: application: name: order-service cloud: nacos: config:server-addr: 10.10.15.5:8848 discovery:server-addr: 10.10.15.5:8848 sentinel: eager: true transport:dashboard: 10.10.15.5:8080 datasource:ds1: nacos: server-addr: 10.10.15.5:8848 dataId: ${spring.application.name}-flow-rules data-type: json rule-type: flow

到此這篇關(guān)于Spring cloud 限流的多種方式的文章就介紹到這了,更多相關(guān)Spring cloud 限流內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 亚洲精品国产一区二区三区四区 | 欧美黄色成人 | 日本最黄视频 | 亚洲精品国产精品精 | 亚洲一区免费 | 亚洲精品第1页 | 国产欧美日韩另类 | 国产理论自拍 | 国产精品第二页 | 国产一区二区免费在线 | 一级毛片女学护士 | 亚洲欧美中文字幕高清在线一 | 福利在线一区 | 亚洲国产精品一区二区九九 | 看黄色一级 | 艾小青亚洲专区在线播放 | 亚州成人 | 久久日本精品99久久久久 | 爱呦视频在线播放网址 | 久久视频精品a线视频在线观看 | a级一级片| 免费在线观看日韩 | 美女被网站免费看九色视频 | 五月天婷婷在线视频 | 在线观看免费高清激情爱爱 | 国产免费福利体检区久久 | 国产91综合 | 风间由美中文字幕亚洲一区 | 91丁香亚洲综合社区 | 国产精品网红 | 国产毛片一区 | 亚洲第九十九页 | 精品一区二区三区色花堂 | 黄色短视频免费 | 国产三级精品三级在线观看 | 国产特黄一级一片免费 | 欧美精品一级毛片 | 午夜水蜜桃视频在线观看 | 日本一级毛片视频在线看 | 欧美日韩亚洲国产一区二区综合 | 哪有黄色网址 |