分散式限流

一、分散式限流實現秒殺

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

下面是一個實現秒殺的分散式限流代碼示例:

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

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 13:11
下一篇 2024-12-12 13:11

相關推薦

  • KeyDB Java:完美的分散式高速緩存方案

    本文將從以下幾個方面對KeyDB Java進行詳細闡述:KeyDB Java的特點、安裝和配置、使用示例、性能測試。 一、KeyDB Java的特點 KeyDB Java是KeyD…

    編程 2025-04-29
  • Java Hmily分散式事務解決方案

    分散式系統是現在互聯網公司架構中的必備項,但隨著業務的不斷擴展,分散式事務的問題也日益凸顯。為了解決分散式事務問題,Java Hmily分散式事務解決方案應運而生。本文將對Java…

    編程 2025-04-28
  • JL Transaction – 實現分散式事務管理的利器

    本文將為大家介紹JL Transaction,這是一款可以實現分散式事務管理的開源事務框架,它可以幫助企業在分散式環境下有效地解決事務的一致性問題,從而保障系統的穩定性和可靠性。 …

    編程 2025-04-28
  • 使用RPC研發雲實現分散式服務交互

    本文將基於RPC研發雲,闡述分散式服務交互實現的過程和實現方式。 一、RPC研發雲簡介 RPC研發雲是一種基於分散式架構的服務框架,在處理不同語言之間的通信上變得越來越流行。通過使…

    編程 2025-04-28
  • 分散式文件系統數據分布演算法

    數據分布演算法是分散式文件系統中的重要技術之一,它能夠實現將文件分散存儲於各個節點上,提高系統的可靠性和性能。在這篇文章中,我們將從多個方面對分散式文件系統數據分布演算法進行詳細的闡述…

    編程 2025-04-27
  • 使用Spring Cloud Redis實現分散式緩存管理

    一、背景介紹 在分散式互聯網應用中,緩存技術扮演著非常重要的角色。緩存技術能夠有效減輕資料庫的訪問壓力,提高應用的訪問速度。在分散式應用中,如何統一管理分散式緩存成為了一項挑戰。本…

    編程 2025-04-24
  • 使用Kubernetes(K8s)搭建分散式系統

    一、Kubernetes概述 Kubernetes是一個用於自動部署、擴展和管理容器化應用程序的開源平台。其提供了高可用性、自我修復能力和易於擴展的特徵,使得大規模、高度可用的分布…

    編程 2025-04-24
  • 分散式鎖的實現與應用——以Redisson為例

    分散式鎖是保障在分散式系統中多個節點之間資源互斥的重要手段,而Redisson是Redis官方推薦的Java客戶端,不僅提供基於Java語言對Redis的操作介面,還提供了分散式鎖…

    編程 2025-04-23
  • 詳解SpringBoot分散式鎖

    一、為什麼需要分散式鎖? 在分散式系統中,多個節點需要對同一資源進行並發訪問和操作。如果沒有分散式鎖,很容易出現資源競爭問題,引發數據錯誤或系統崩潰的風險。 例如,假設有兩個客戶端…

    編程 2025-04-23
  • Zookeeper Docker:實現可擴展、可靠的分散式協調服務

    一、Docker容器技術 Docker是一種基於容器的虛擬化技術,它可以將應用程序及其依賴項打包為一個可移植、自包含的容器。Docker使得開發人員可以使用相同的環境在不同的計算機…

    編程 2025-04-23

發表回復

登錄後才能評論