天天看點

java開源多租戶_java B2B2C Springcloud多租戶電子商城系統- gateway(實作限流)

限流一般有兩個實作方式,令牌桶和漏桶

需要JAVA Spring Cloud大型企業分布式微服務雲建構的B2B2C電子商務平台源碼:壹零叁八柒柒肆六二六

令牌桶是初始化令牌(容器)的個數,通過拿走裡邊的令牌就能通過, 沒有令牌不能報錯,可以設定向容器中增加令牌的速度和最大個數

漏桶是向裡邊放入請求,當請求數量達到最大值後,丢棄,漏桶中的資料以一定速度流出,沒有則不流出

令牌桶實作方式如下:

pom

com.github.vladimir-bukhtoyarov

bucket4j-core

4.0.0

建立下邊類并且繼承下邊類

package com.gla.datacenter.filter;

import io.github.bucket4j.Bandwidth;

import io.github.bucket4j.Bucket;

import io.github.bucket4j.Bucket4j;

import io.github.bucket4j.Refill;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.cloud.gateway.filter.GatewayFilter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import org.springframework.core.Ordered;

import org.springframework.http.HttpStatus;

import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

import java.time.Duration;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

public class GatewayRateLimitFilterByIP implements GatewayFilter, Ordered {

private final Logger log = LoggerFactory.getLogger(GatewayRateLimitFilterByIP.class);

private static final Map LOCAL_CACHE = new ConcurrentHashMap<>();

int capacity;

int refillTokens;

Duration refillDuration;

public GatewayRateLimitFilterByIP() {

}

public GatewayRateLimitFilterByIP(int capacity, int refillTokens, Duration refillDuration) {

this.capacity = capacity;

this.refillTokens = refillTokens;

this.refillDuration = refillDuration;

}

private Bucket createNewBucket() {

Refill refill = Refill.of(refillTokens, refillDuration);

Bandwidth limit = Bandwidth.classic(capacity, refill);

return Bucket4j.builder().addLimit(limit).build();

}

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();

//若ip不存在則建立一個Bucket(令牌桶)

Bucket bucket = LOCAL_CACHE.computeIfAbsent(ip, k -> createNewBucket());

log.info("IP:{} ,令牌通可用的Token數量:{} " ,ip,bucket.getAvailableTokens());

if (bucket.tryConsume(1)) {

return chain.filter(exchange);

} else {

//當可用的令牌書為0是,進行限流傳回429狀态碼

log.error("IP:{} ,限制通路:{} " ,ip,bucket.getAvailableTokens());

exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);

return exchange.getResponse().setComplete();

}

}

@Override

public int getOrder() {

return -1000;

}

public static Map getLocalCache() {

return LOCAL_CACHE;

}

public int getCapacity() {

return capacity;

}

public void setCapacity(int capacity) {

this.capacity = capacity;

}

public int getRefillTokens() {

return refillTokens;

}

public void setRefillTokens(int refillTokens) {

this.refillTokens = refillTokens;

}

public Duration getRefillDuration() {

return refillDuration;

}

public void setRefillDuration(Duration refillDuration) {

this.refillDuration = refillDuration;

}

}

配置路由

@Bean

public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {

//生成比目前時間早一個小時的UTC時間

ZonedDateTime minusTime = LocalDateTime.now().minusHours(1).atZone(ZoneId.systemDefault());

return builder.routes()

.route(r ->r.path("/demo/**")

//過濾器

.filters(f -> f.filter(new APIGatewayFilter())

.filter(new GatewayRateLimitFilterByIP(10,1, Duration.ofSeconds(1))))

.uri("http://192.168.26.113:8001/demo").order(0).id("demo_route"))

.route(r ->r.path("/test")

.uri("http://192.168.26.113/system/nav/login").id("jd_route")

)

build();

}