一、分散式限流實現秒殺
在高並發場景下,流量很大的時候需要進行限流操作,否則可能會出現系統崩潰或者對相關業務造成影響。秒殺場景是一個典型的高並發場景。很多網站都會在一定時間內提供限量商品,用戶搶購時都是在同一時間內進行,此時需要限制每個用戶的請求次數,否則會出現惡意刷單等現象。而分散式限流可以使我們更加高效地解決這個問題。
下面是一個實現秒殺的分散式限流代碼示例:
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