Sentinel併發限流不精確-之責任鏈
阿新 • • 發佈:2020-12-26
在之前調研Sentinel的過程中,為了準備分享內容,自己就簡單的寫了一些測試程式碼,不過在測試中遇到了一些問題,其中有一個問題就是Sentinel流控在併發情況下限流並不精確,當時我還在想,這個我在做分享的時候該怎麼來自圓其說呢,所以覺得比較有意思,在這裡做一個記錄。同時在排查這個問題的過程中,為了說清楚問題原因,我覺得有必要理一下它的責任鏈,所以副標題就是Sentinel的責任鏈。
***
# 一、問題起源
在這裡我直接上我的測試程式碼,我的本意是要起10個執行緒同時去請求這個資源,每個執行緒輪詢10次。同時,對於這個資源我設定了限流規則為QPS=1。這也就意味著我這10個執行緒共100個請求,正確的結果應該是成功1個,阻塞99個。
~~~java
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 流量控制演示
*/
public class FlowQpsDemo_Bug {
private static final String SOURCE_KEY = "CESHI_KEY";
private static AtomicInteger pass = new AtomicInteger();
private static AtomicInteger block = new AtomicInteger();
private static AtomicInteger total = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
initFlowQpsRule();
CountDownLatch start = new CountDownLatch(1);
CountDownLatch end = new CountDownLatch(10);
for (int i = 0;i < 10;i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
start.await();
} catch (InterruptedException e) {
}
for (int i = 0;i < 10;i++) {
fun();
}
end.countDown();
}
}).start();
}
start.countDown();
end.await();
System.out.println("total=" + total.get() + " pass=" + pass.get() + " block=" + block.get());
}
public static void fun() {
Entry entry = null;
try {
entry = SphU.entry(SOURCE_KEY);
// todo 業務邏輯
pass.incrementAndGet();
} catch (BlockException e1) {
// todo 流控處理
block.incrementAndGet();
} finally {
total.incrementAndGet();
if (entry != null) {
entry.exit();
}
}
}
private static void initFlowQpsRule() {