javascript
spring cloud gateway 网关_微服务网关Spring Cloud Gateway全搞定
一、微服務(wù)網(wǎng)關(guān)Spring Cloud Gateway
1.1 導(dǎo)引
文中內(nèi)容包含:微服務(wù)網(wǎng)關(guān)限流10萬QPS、跨域、過濾器、令牌桶算法。
在構(gòu)建微服務(wù)系統(tǒng)中,必不可少的技術(shù)就是網(wǎng)關(guān)了,從早期的Zuul,到現(xiàn)在的Spring Cloud Gateway,網(wǎng)關(guān)我們用的不可少。
今天我就將沉淀下來的所有與網(wǎng)關(guān)相關(guān)的知識,用一篇文章總結(jié)清楚,希望對愛學習的小伙伴們有所幫助。
本篇文章主要介紹網(wǎng)關(guān)跨域配置,網(wǎng)關(guān)過濾器編寫,網(wǎng)關(guān)的令牌桶算法限流【每秒10萬QPS】
首先我們來看什么是網(wǎng)關(guān)
1.2 什么是微服務(wù)網(wǎng)關(guān)Gateway?
This project provides a library for building an API Gateway on top of Spring WebFlux.gateway官網(wǎng):https://spring.io/projects/spring-cloud-gateway
實現(xiàn)微服務(wù)網(wǎng)關(guān)的技術(shù)有很多,
- nginx Nginx (engine x) 是一個高性能的HTTP和反向代理web服務(wù)器,同時也提供了IMAP/POP3/SMTP服務(wù)
- zuul ,Zuul 是 Netflix 出品的一個基于 JVM 路由和服務(wù)端的負載均衡器。
- spring-cloud-gateway, 是spring 出品的 基于spring 的網(wǎng)關(guān)項目,集成斷路器,路徑重寫,性能比Zuul好。
我們使用gateway這個網(wǎng)關(guān)技術(shù),無縫銜接到基于spring cloud的微服務(wù)開發(fā)中來。
1.3 微服務(wù)為什么要使用網(wǎng)關(guān)呢?
不同的微服務(wù)一般會有不同的網(wǎng)絡(luò)地址,而外部客戶端可能需要調(diào)用多個服務(wù)的接口才能完成一個業(yè)務(wù)需求,如果讓客戶端直接與各個微服務(wù)通信,會有以下的問題:
以上這些問題可以借助網(wǎng)關(guān)解決。
網(wǎng)關(guān)是介于客戶端和服務(wù)器端之間的中間層,所有的外部請求都會先經(jīng)過 網(wǎng)關(guān)這一層。也就是說,API 的實現(xiàn)方面更多地考慮業(yè)務(wù)邏輯,而安全、性能、監(jiān)控可以交由 網(wǎng)關(guān)來做,這樣既提高業(yè)務(wù)靈活性又不缺安全性,典型的架構(gòu)圖如圖所示:
1.4 微服務(wù)網(wǎng)關(guān)的優(yōu)點
- 安全 ,只有網(wǎng)關(guān)系統(tǒng)對外進行暴露,微服務(wù)可以隱藏在內(nèi)網(wǎng),通過防火墻保護。
- 易于監(jiān)控。可以在網(wǎng)關(guān)收集監(jiān)控數(shù)據(jù)并將其推送到外部系統(tǒng)進行分析。
- 易于認證。可以在網(wǎng)關(guān)上進行認證,然后再將請求轉(zhuǎn)發(fā)到后端的微服務(wù),而無須在每個微服務(wù)中進行認證。
- 減少了客戶端與各個微服務(wù)之間的交互次數(shù)
- 易于統(tǒng)一授權(quán)。
1.5 總結(jié)
微服務(wù)網(wǎng)關(guān)就是一個系統(tǒng),通過暴露該微服務(wù)網(wǎng)關(guān)系統(tǒng),方便我們進行相關(guān)的鑒權(quán),安全控制,日志統(tǒng)一處理,易于監(jiān)控的相關(guān)功能。
二、微服務(wù)網(wǎng)關(guān)搭建及配置
2.1 微服務(wù)網(wǎng)關(guān)微服務(wù)搭建
由于我們開發(fā)的系統(tǒng) 有包括前臺系統(tǒng)和后臺系統(tǒng),后臺的系統(tǒng)給管理員使用。那么也需要調(diào)用各種微服務(wù),所以我們針對管理后臺搭建一個網(wǎng)關(guān)微服務(wù)。分析如下:
搭建步驟:
(1)依賴坐標pom.xml:
<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> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> 復(fù)制代碼(2)啟動引導(dǎo)類:GatewayApplication
@SpringBootApplication @EnableEurekaClient public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);} } 復(fù)制代碼(3)在resources下創(chuàng)建application.yml
spring:application:name: apigatewaycloud:gateway:routes:- id: openuri: lb://openpredicates:- Path=/open/**filters:- StripPrefix= 1- id: systemuri: lb://systempredicates:- Path=/system/**filters:- StripPrefix= 1 server:port: 9999 eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eurekainstance:prefer-ip-address: true 復(fù)制代碼參考官方手冊:
http://cloud.spring.io/spring-clou…
2.2 微服務(wù)網(wǎng)關(guān)跨域
在啟動類GatewayApplication中,加入跨域配置代碼如下
@Bean public CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.addAllowedMethod("*");//支持所有方法config.addAllowedOrigin("*");//跨域處理 允許所有的域config.addAllowedHeader("*");//支持所有請求頭UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/**", config);//匹配所有請求return new CorsWebFilter(source); } 復(fù)制代碼三、微服務(wù)網(wǎng)關(guān)過濾器
我們可以通過網(wǎng)關(guān)過濾器,實現(xiàn)一些邏輯的處理,比如ip黑白名單攔截、特定地址的攔截等。下面的代碼中做了兩個過濾器,并且設(shè)定的先后順序。
(1)在網(wǎng)關(guān)微服務(wù)中創(chuàng)建IpFilter,無需配置其他,注冊到Spring容器即可生效
@Component public class IpFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();InetSocketAddress remoteAddress = request.getRemoteAddress();//TODO 設(shè)置ip白名單System.out.println("ip:"+remoteAddress.getHostName());return chain.filter(exchange);}@Overridepublic int getOrder() {return 1;} } 復(fù)制代碼(2)在網(wǎng)關(guān)微服務(wù)中創(chuàng)建UrlFilter,無需配置其他,注冊到Spring容器即可生效
@Component public class UrlFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();String url = request.getURI().getPath();//TODO 攔截特定URL地址System.out.println("url:"+url);return chain.filter(exchange);}@Overridepublic int getOrder() {return 2;} } 復(fù)制代碼四、網(wǎng)關(guān)限流每秒10萬請求
? 我們之前說過,網(wǎng)關(guān)可以做很多的事情,比如,限流,當我們的系統(tǒng) 被頻繁的請求的時候,就有可能 將系統(tǒng)壓垮,所以 為了解決這個問題,需要在每一個微服務(wù)中做限流操作,但是如果有了網(wǎng)關(guān),那么就可以在網(wǎng)關(guān)系統(tǒng)做限流,因為所有的請求都需要先通過網(wǎng)關(guān)系統(tǒng)才能路由到微服務(wù)中。
4.1 限流實現(xiàn)思路分析
看圖就完了,非常簡單!
4.2 令牌桶算法 介紹
令牌桶算法是比較常見的限流算法之一,大概描述如下:
1)所有的請求在處理之前都需要拿到一個可用的令牌才會被處理; 2)根據(jù)限流大小,設(shè)置按照一定的速率往桶里添加令牌; 3)桶設(shè)置最大的放置令牌限制,當桶滿時、新添加的令牌就被丟棄或者拒絕; 4)請求達到后首先要獲取令牌桶中的令牌,拿著令牌才可以進行其他的業(yè)務(wù)邏輯,處理完業(yè)務(wù)邏輯之后,將令牌直接刪除; 5)令牌桶有最低限額,當桶中的令牌達到最低限額的時候,請求處理完之后將不會刪除令牌,以此保證足夠的限流
如下圖:
這個算法的實現(xiàn),有很多技術(shù),Guava(讀音: 瓜哇)是其中之一,redis客戶端也有其實現(xiàn)。
4.3 網(wǎng)關(guān)限流代碼實現(xiàn)
需求:每個ip地址1秒內(nèi)只能發(fā)送10萬請求,多出來的請求返回429錯誤。
代碼實現(xiàn):
(1)spring cloud gateway 默認使用redis的RateLimter限流算法來實現(xiàn)。所以我們要使用首先需要引入redis的依賴
<!--redis--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId><version>2.1.3.RELEASE</version> </dependency> 復(fù)制代碼(2)定義KeyResolver
在GatewayApplicatioin引導(dǎo)類中添加如下代碼,KeyResolver用于計算某一個類型的限流的KEY也就是說,可以通過KeyResolver來指定限流的Key。
//定義一個KeyResolver@Beanpublic KeyResolver ipKeyResolver() {return new KeyResolver() {@Overridepublic Mono<String> resolve(ServerWebExchange exchange) {return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}};} 復(fù)制代碼(3)修改application.yml中配置項,指定限制流量的配置以及REDIS的配置,修改后最終配置如下:
spring:application:name: apigatewaycloud:gateway:routes:- id: openuri: lb://openpredicates:- Path=/open/**filters:- StripPrefix= 1- name: RequestRateLimiter #請求數(shù)限流 名字不能隨便寫 args:key-resolver: "#{@ipKeyResolver}"redis-rate-limiter.replenishRate: 1redis-rate-limiter.burstCapacity: 1- id: systemuri: lb://systempredicates:- Path=/system/**filters:- StripPrefix= 1# 配置Redis 127.0.0.1可以省略配置redis:host: 101.57.2.128port: 6379 server:port: 9999 eureka:client:service-url:defaultZone: http://127.0.0.1:100/eurekainstance:prefer-ip-address: true 復(fù)制代碼解釋:
- burstCapacity:令牌桶總?cè)萘俊?/li>
- replenishRate:令牌桶每秒填充平均速率。
- key-resolver:用于限流的鍵的解析器的 Bean 對象的名字。它使用 SpEL 表達式根據(jù)#{@beanName}從 Spring 容器中獲取 Bean 對象。
通過在replenishRate和中設(shè)置相同的值來實現(xiàn)穩(wěn)定的速率burstCapacity。設(shè)置burstCapacity高于時,可以允許臨時突發(fā)replenishRate。在這種情況下,需要在突發(fā)之間允許速率限制器一段時間(根據(jù)replenishRate),因為2次連續(xù)突發(fā)將導(dǎo)致請求被丟棄(HTTP 429 - Too Many Requests)
key-resolver: "#{@userKeyResolver}" 用于通過SPEL表達式來指定使用哪一個KeyResolver.
如上配置:
表示 一秒內(nèi),允許 一個請求通過,令牌桶的填充速率也是一秒鐘添加一個令牌。
最大突發(fā)狀況 也只允許 一秒內(nèi)有一次請求,可以根據(jù)業(yè)務(wù)來調(diào)整 。
(4)測試時需要注意服務(wù)啟動順序,這里需要依賴于Redis,所以首先要啟動redis
- 啟動redis
- 啟動注冊中心
- 啟動商品微服務(wù)
- 啟動gateway網(wǎng)關(guān)
- 打開瀏覽器 http://localhost:9999/open
- 快速刷新,當1秒內(nèi)發(fā)送超過10萬次請求,就會返回429錯誤。
那么問題來了:怎么發(fā)送10萬次請求呢? 知道的同學,請在留言區(qū)評論。不知道下次我寫篇壓測來個百萬QPS!
總結(jié)
以上是生活随笔為你收集整理的spring cloud gateway 网关_微服务网关Spring Cloud Gateway全搞定的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信号扫描_图文并茂,一文读懂信号源
- 下一篇: 输入文字自动生成图片_原来Word还可以