关于java:sentinel令牌桶限流算法

14次阅读

共计 2539 个字符,预计需要花费 7 分钟才能阅读完成。

钻研一下 sentinel 实现的外围算法

<!-- replace here with the latest version -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.3</version>
</dependency>

官网应用阐明

List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("HelloWorld");
// set limit qps to 20
rule.setCount(20);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rules.add(rule);
FlowRuleManager.loadRules(rules);
try (Entry entry = SphU.entry("HelloWorld")) {
    // Your business logic here.
    System.out.println("hello world");
} catch (BlockException e) {
    // Handle rejected request.
    e.printStackTrace();}
// try-with-resources auto exit

为了看一下外围实现环节,为了更直观的进行了解,这里把一秒分成两个窗口,即每个窗口 slidingWindowSize 为 500, 并且进行了简洁的从新编写

    private static long slidingWindowSize = 500L;
    private AtomicReferenceArray<Item> array = new AtomicReferenceArray<Item>(2);
    private ReentrantLock lock = new ReentrantLock();
    private long permitsPerSecond; // 设定每秒容许的 qps

入口办法

    public boolean entry() {
        try {long currentTimeMillis = System.currentTimeMillis();
            int index = findSlidingWindowIndex(currentTimeMillis);
            long slidingWindowStart = findSlidingWindowStart(currentTimeMillis);
            Item item = currentItem(index, slidingWindowStart);
            if (item == null) {return true;}
            if (accumulatedPassQps(1 - index, item) > permitsPerSecond) {return false;}
            item.passIncrement();
            return true;
        } catch (Exception ex) {return true;}
    }

累计曾经通过的 qps

    private long accumulatedPassQps(int index, Item item) {Item other = array.get(index);
        if (other == null
                || (Math.abs(other.getSlidingWindowStart() - item.getSlidingWindowStart()) > slidingWindowSize)) {return item.passValue();
        }

        return other.passValue() + item.passValue();
    }

以后是哪个工夫窗口

    private Item currentItem(int index, long slidingWindowStart) {while (true) {Item previous = array.get(index);
            if (previous == null) {Item item = new Item(slidingWindowStart);
                if (array.compareAndSet(index, null, item)) {return item;} else {Thread.yield();
                }

            } else if (slidingWindowStart == previous.getSlidingWindowStart()) {return previous;} else if (slidingWindowStart > previous.getSlidingWindowStart()) {if (lock.tryLock()) {
                    try {return previous.reset(slidingWindowStart);
                    } finally {lock.unlock();
                    }
                } else {Thread.yield();
                }
            } else {return null;}
        }
    }

    private long findSlidingWindowStart(long timeMillis) {return timeMillis - timeMillis % slidingWindowSize;}

    private int findSlidingWindowIndex(long timeMillis) {return (int) ((timeMillis / slidingWindowSize) % 2);
    }

Item 封装的内容

    private long slidingWindowStart;
    private LongAdder accu;
    public Item reset(long slidingWindowStart) {
        this.slidingWindowStart = slidingWindowStart;
        accu.reset();
        return this;
    }

    public long passValue() {return accu.sum();
    }

    public void passIncrement() {accu.increment();
    }

    public long getSlidingWindowStart() {return slidingWindowStart;}

正文完
 0