一、分散式限流實現秒殺
在高並發場景下,流量很大的時候需要進行限流操作,否則可能會出現系統崩潰或者對相關業務造成影響。秒殺場景是一個典型的高並發場景。很多網站都會在一定時間內提供限量商品,用戶搶購時都是在同一時間內進行,此時需要限制每個用戶的請求次數,否則會出現惡意刷單等現象。而分散式限流可以使我們更加高效地解決這個問題。
下面是一個實現秒殺的分散式限流代碼示例:
public boolean tryAcquireSeckill() {
// 每秒放行5次請求
RateLimiter rateLimiter = RateLimiter.create(5);
return rateLimiter.tryAcquire();
}
二、分散式限流三種演算法
分散式限流主要包括計數器演算法、令牌桶演算法和漏桶演算法。
計數器演算法是指通過統計一段時間內的請求次數,當超過一定的閾值時就進行限流操作。
public class CountAlgorithm {
private static AtomicInteger count = new AtomicInteger(0);
public static boolean tryAcquire() {
int newCount = count.incrementAndGet();
if(newCount > 10) {
return false;
} else {
return true;
}
}
}
令牌桶演算法則是需要令牌才能進行訪問的一種演算法。可以設置每秒鐘發放多少個令牌,每發放一個令牌後就會扣除一個。當桶內令牌數不足時,無法進行訪問。
public class TokenBucketAlgorithm {
private static RateLimiter rateLimiter = RateLimiter.create(10);
public static boolean tryAcquire() {
return rateLimiter.tryAcquire();
}
}
漏桶演算法則是保證一定的流量輸出,防止流量被突發的請求消耗。
public class LeakyBucketAlgorithm {
// 桶容量
private static int capacity = 10;
// 水流速度
private static int rate = 1;
// 時間間隔
private static int timeInterval = 1000;
// 當前水量
private static int water = 0;
// 上次漏水的時間
private static long lastTime = System.currentTimeMillis();
public static synchronized boolean tryAcquire() {
// 計算流入的水量
long now = System.currentTimeMillis();
water = Math.max(0, water - (int)((now - lastTime) / timeInterval) * rate);
lastTime = now;
if(water < capacity) {
water++;
return true;
} else {
return false;
}
}
}
三、分散式限流器
分散式限流器是一種通用的限流框架,可以在各種業務場景下使用。使用該框架可以有效控制流量,防止系統崩潰。
下面是一個基於Google Guava庫實現的分散式限流器:
public class RateLimiterDecorator {
private static final String SEPARATOR = "_";
private int permitsPerSecond;
private LoadingCache loadingCache;
private Function keyMapper;
public RateLimiterDecorator(int permitsPerSecond, Function keyMapper) {
this.permitsPerSecond = permitsPerSecond;
this.keyMapper = keyMapper;
CacheLoader loader = new CacheLoader() {
@Override
public RateLimiter load(String key) throws Exception {
return RateLimiter.create(permitsPerSecond);
}
};
loadingCache = CacheBuilder.newBuilder().build(loader);
}
public boolean tryAcquire(T key) {
try {
return loadingCache.get(keyMapper.apply(key)).tryAcquire();
} catch (ExecutionException e) {
e.printStackTrace();
return false;
}
}
}
四、分散式限流框架
分散式限流框架是一種將限流邏輯封裝在框架中,可以通過配置參數實現對流量的限制,從而防止系統崩潰,同時可以有效提高程序的可維護性。
下面是一個基於Spring Cloud Gateway和Redis實現的分散式限流框架:
public class RateLimiterFilter implements GlobalFilter, Ordered {
private static final String REQUEST_PATH_KEY = "request_path";
private static final String REQUEST_METHOD_KEY = "request_method";
private static final String ALLOW_PATH_PATTERN_KEY = "allow_path_pattern";
private static final String RATE_LIMIT_KEY = "rate_limit";
private static final String REDIS_RATE_LIMIT_KEY_PREFIX = "rate-limit:";
private StringRedisTemplate redisTemplate;
private PathMatcher pathMatcher = new AntPathMatcher();
public RateLimiterFilter(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String requestMethod = exchange.getRequest().getMethodValue();
String requestPath = exchange.getRequest().getPath().value();
// 遍歷配置文件中的限流規則
redisTemplate.opsForHash().entries(RATE_LIMIT_KEY).entrySet().stream()
.filter(entry -> {
String allowPathPattern = (String)entry.getValue();
return pathMatcher.match(allowPathPattern, requestPath);
})
.forEach(entry -> {
String redisKey = REDIS_RATE_LIMIT_KEY_PREFIX + entry.getKey() + ":" + requestMethod;
long count = redisTemplate.opsForValue().increment(redisKey, 1);
if(count == 1) {
redisTemplate.expire(redisKey, 60, TimeUnit.SECONDS);
}
long threshold = Long.parseLong((String)entry.getValue());
if(count > threshold) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
});
exchange.getAttributes().put(REQUEST_PATH_KEY, requestPath);
exchange.getAttributes().put(REQUEST_METHOD_KEY, requestMethod);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1000;
}
}
五、分散式限流方案
針對不同的系統架構和業務場景,可以選擇不同的分散式限流方案。比如基於Redis的分散式限流、基於Zookeeper的分散式限流等。下面是一個基於Redis的分散式限流代碼示例:
public class RedisRateLimiter {
private static final String REDIS_RATE_LIMIT_KEY_PREFIX = "rate-limit:";
private StringRedisTemplate redisTemplate;
public RedisRateLimiter(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public boolean tryAcquire(String key, int permits, int seconds) {
String redisKey = REDIS_RATE_LIMIT_KEY_PREFIX + key;
long count = redisTemplate.opsForValue().increment(redisKey, 1);
if(count == 1) {
redisTemplate.expire(redisKey, seconds, TimeUnit.SECONDS);
}
long threshold = permits;
if(count > threshold) {
return false;
} else {
return true;
}
}
}
六、分散式限流組件
隨著分散式限流的應用日益廣泛,市面上也出現了一些比較成熟的分散式限流組件,如Sentinel、Zookeeper。這些組件具有使用方便、穩定性高的特點,可以為我們提供基礎限流組件,加快開發效率。
下面是一個基於Sentinel的分散式限流代碼示例:
public class SentinelRateLimiter {
private static final String RESOURCE_NAME = "resource_name";
private static final String FLOW_CONTROLLER = "flow_controller";
private static final String THRESHOLD_TYPE = "grade";
public boolean tryAcquire(String resourceId, double permits) {
Entry entry = null;
try {
entry = SphU.entry(resourceId, ResourceType.COMMON, EntryType.IN);
if(entry != null) {
// do something
return true;
}
} catch (BlockException e) {
// handle exception
} finally {
if(entry != null) {
entry.exit();
}
}
return false;
}
public static void initFlowRule(double threshold) {
List rules = new ArrayList();
FlowRule rule = new FlowRule();
rule.setClusterMode(false);
rule.setCount(threshold);
rule.setResource(RESOURCE_NAME);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
rule.setStrategy(RuleConstant.STRATEGY_DIRECT);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
rule.setWarmUpPeriodSec(10);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
public static void registerFlowController(double threshold) {
String type = THRESHOLD_TYPE;
AbstractRule rule = null;
switch(type) {
case RuleConstant.FLOW_GRADE_QPS:
rule = new FlowRule(RESOURCE_NAME)
.setCount(threshold)
.setGrade(RuleConstant.FLOW_GRADE_QPS);
break;
case RuleConstant.FLOW_GRADE_THREAD:
rule = new DegradeRule(RESOURCE_NAME)
.setCount(threshold)
.setGrade(RuleConstant.FLOW_GRADE_THREAD);
break;
case RuleConstant.FLOW_GRADE_EXCEPTION_RATIO:
rule = new DegradeRule(RESOURCE_NAME)
.setCount(threshold)
.setGrade(RuleConstant.FLOW_GRADE_EXCEPTION_RATIO);
break;
default:
break;
}
if(rule != null) {
FlowRuleManager.register2Property(rule.property());
FLOW_CONTROLLER = type;
}
}
}
七、阿里哨兵分散式限流原理
阿里哨兵是一個針對分散式系統的流量控制組件,它通過不同的限流策略進行流量控制,從而防止流量被突發的請求消耗。
下面是阿里哨兵的分散式限流原理:
首先,哨兵會將應用程序的不同資源進行抽象,並且對每個資源設置不同的閾值。然後,每個應用程序都需要從阿里雲哨兵服務中獲取相關資源的限流規則,當應用程序達到限流規則的閾值時哨兵就會進行限流控制。哨兵還可以通過實時監控和動態感知應用程序資源的變化,從而實現動態調整限流策略的功能。
八、分散式潮流控制器
分散式潮流控制是指在網路系統中對電力負荷進行控制,從而保障電網的正常運行。分散式潮流控制器可以通過協調不同的電力負荷,使得電網的總負荷保持在一個正常的範圍內,從而避免電網出現過載狀態。
下面是一個分散式潮流控制器的代碼示例:
public class DistributedPowerFlowController { private static final String LOAD_NODE = "load";
private static final String GENERATOR_NODE = "generator";
private static final String TRANSFORMER_NODE = "transformer";
private static double[] load = {100, 100, 100};
private static double[] generator = {200, 200, 200};
private static double[] transformer = {300, 300, 300};
private static final double[][] Y = {
{1, -1, 0},
{0, 1, -1},
{-1, 0, 1}
};
public static double[] getFlow() {
// 構造潮流控制方程
double[][] A = new double[3][3];
double[] b = new double[3];
for(int i=0; i<Y.length; i++) {
for(int j=0; j<Y[i].length; j++) {
if(i == j)
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/245866.html
微信掃一掃
支付寶掃一掃