钻研一下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 20rule.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; }