研究一下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;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。