基於Spring Cloud、oAuth2.0開發基於Vue先後分離的開發平臺,支持帳號、短信、SSO等多種登陸,提供配套視頻開發教程。react
SpringCloudGateway是Spring官方基於Spring 5.0,Spring Boot 2.0和Project Reactor等技術開發的網關,Spring雲網關旨在提供一種簡單而有效的路由API的方法。Spring Cloud Gateway做爲Spring Cloud生態系中的網關,目標是替代Netflix ZUUL,其不只提供統一的路由方式,而且基於Filter鏈的方式提供了網關基本的功能,例如:安全,監控/埋點,和限流等。git
Zuul:構建高可用網關之多維度限流redis
<!--spring cloud gateway依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--基於 reactive stream 的redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency>
spring: cloud: gateway: routes: - id: requestratelimiter_route uri: lb://pigx-upms order: 10000 predicates: - Path=/admin/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 1 # 令牌桶的容積 redis-rate-limiter.burstCapacity: 3 # 流速 每秒 key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表達式去的對應的bean - StripPrefix=1
配置bean,多維度限流量的入口spring
/** * 自定義限流標誌的key,多個維度能夠從這裏入手 * exchange對象中獲取服務ID、請求信息,用戶信息等 */ @Bean KeyResolver remoteAddrKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); }
OK 完成。安全
併發5個線程。
併發
咱們使用redis的monitor 命令,實時查看redis 的操做狀況。
會發如今redis中會操做兩個keyspring-boot
Spring Cloud Gateway 默認實現 Redis限流,若是擴展只須要實現ratelimter接口便可。測試
public Mono<Response> isAllowed(String routeId, String id) { Config routeConfig = getConfig().getOrDefault(routeId, defaultConfig); int replenishRate = routeConfig.getReplenishRate(); int burstCapacity = routeConfig.getBurstCapacity(); try { List<String> keys = getKeys(id); returns unixtime in seconds. List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "", Instant.now().getEpochSecond() + "", "1"); // 這裏是核心,執行redis 的LUA 腳本。 Flux<List<Long>> flux = this.redisTemplate.execute(this.script, keys, scriptArgs); return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L))) .reduce(new ArrayList<Long>(), (longs, l) -> { longs.addAll(l); return longs; }) .map(results -> { boolean allowed = results.get(0) == 1L; Long tokensLeft = results.get(1); Response response = new Response(allowed, getHeaders(routeConfig, tokensLeft)); if (log.isDebugEnabled()) { log.debug("response: " + response); } return response; }); } catch (Exception e) { log.error("Error determining if user allowed from redis", e); } return Mono.just(new Response(true, getHeaders(routeConfig, -1L))); }