+ * 1529399827825,total:0, pass:0, block:0 + * 1529399828825,total:4263, pass:100, block:4164 + * 1529399829825,total:19179, pass:4, block:19176 // circuit breaker opens + * 1529399830824,total:19806, pass:0, block:19806 + * 1529399831825,total:19198, pass:0, block:19198 + * 1529399832824,total:19481, pass:0, block:19481 + * 1529399833826,total:19241, pass:0, block:19241 + * 1529399834826,total:17276, pass:0, block:17276 + * 1529399835826,total:18722, pass:0, block:18722 + * 1529399836826,total:19490, pass:0, block:19492 + * 1529399837828,total:19355, pass:0, block:19355 + * 1529399838827,total:11388, pass:0, block:11388 + * 1529399839829,total:14494, pass:104, block:14390 // After 10 seconds, the system restored + * 1529399840854,total:18505, pass:0, block:18505 + * 1529399841854,total:19673, pass:0, block:19676 + *+ * + * @author jialiang.linjl + * @author Eric Zhao + */ +public class SlowRatioCircuitBreakerDemo { + + private static final String KEY = "some_method"; + + private static volatile boolean stop = false; + private static int seconds = 120; + + private static AtomicInteger total = new AtomicInteger(); + private static AtomicInteger pass = new AtomicInteger(); + private static AtomicInteger block = new AtomicInteger(); + + public static void main(String[] args) throws Exception { + initDegradeRule(); + registerStateChangeObserver(); + startTick(); + + int concurrency = 8; + for (int i = 0; i < concurrency; i++) { + Thread entryThread = new Thread(() -> { + while (true) { + Entry entry = null; + try { + entry = SphU.entry(KEY); + pass.incrementAndGet(); + // RT: [40ms, 60ms) + sleep(ThreadLocalRandom.current().nextInt(40, 60)); + } catch (BlockException e) { + block.incrementAndGet(); + sleep(ThreadLocalRandom.current().nextInt(5, 10)); + } finally { + total.incrementAndGet(); + if (entry != null) { + entry.exit(); + } + } + } + }); + entryThread.setName("sentinel-simulate-traffic-task-" + i); + entryThread.start(); + } + } + + private static void registerStateChangeObserver() { + EventObserverRegistry.getInstance().addStateChangeObserver("logging", + (prevState, newState, rule, snapshotValue) -> { + if (newState == State.OPEN) { + System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(), + TimeUtil.currentTimeMillis(), snapshotValue)); + } else { + System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(), + TimeUtil.currentTimeMillis())); + } + }); + } + + private static void initDegradeRule() { + List
+ * If {@link com.alibaba.csp.sentinel.slots.block.RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER} is set, incoming + * requests are passing at regular interval. When a new request arrives, the + * flow rule checks whether the interval between the new request and the + * previous request. If the interval is less than the count set in the rule + * first. If the interval is large, it will pass the request; otherwise, + * sentinel will calculate the waiting time for this request. If the waiting + * time is longer than the {@link com.alibaba.csp.sentinel.slots.block.flow.FlowRule#maxQueueingTimeMs} set in the rule, + * the request will be rejected immediately. + * + * This method is widely used for pulsed flow. When a large amount of flow + * comes, we don't want to pass all these requests at once, which may drag the + * system down. We can make the system handle these requests at a steady pace by + * using this kind of rules. + * + *
+ * This demo demonstrates how to use {@link com.alibaba.csp.sentinel.slots.block.RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER}. + *
+ * + *+ * {@link #initPaceFlowRule() } create rules that uses + * {@code CONTROL_BEHAVIOR_RATE_LIMITER}. + *
+ * {@link #simulatePulseFlow()} simulates 100 requests that arrives at almost the + * same time. All these 100 request are passed at a fixed interval. + * + *
+ * Run this demo, results are as follows: + *+ * pace behavior + * .... + * 1528872403887 one request pass, cost 9348 ms // every 100 ms pass one request. + * 1528872403986 one request pass, cost 9469 ms + * 1528872404087 one request pass, cost 9570 ms + * 1528872404187 one request pass, cost 9642 ms + * 1528872404287 one request pass, cost 9770 ms + * 1528872404387 one request pass, cost 9848 ms + * 1528872404487 one request pass, cost 9970 ms + * ... + * done + * total pass:100, total block:0 + *+ * + * Then we invoke {@link #initDefaultFlowRule()} to set rules with default behavior, and only 10 + * requests will be allowed to pass, other requests will be rejected immediately. + * + * The output will be like: + *
+ * default behavior + * 1530500101279 one request pass, cost 0 ms + * 1530500101279 one request pass, cost 0 ms + * 1530500101279 one request pass, cost 0 ms + * 1530500101279 one request pass, cost 0 ms + * 1530500101279 one request pass, cost 0 ms + * 1530500101279 one request pass, cost 0 ms + * 1530500101280 one request pass, cost 1 ms + * 1530500101280 one request pass, cost 0 ms + * 1530500101280 one request pass, cost 0 ms + * 1530500101280 one request pass, cost 0 ms + * done + * total pass:10, total block:90 // 10 requests passed, other 90 requests rejected immediately. + *+ * + * @author jialiang.linjl + */ +public class PaceFlowDemo { + + private static final String KEY = "abc"; + + private static volatile CountDownLatch countDown; + + private static final Integer requestQps = 100; + private static final Integer count = 10; + private static final AtomicInteger done = new AtomicInteger(); + private static final AtomicInteger pass = new AtomicInteger(); + private static final AtomicInteger block = new AtomicInteger(); + + public static void main(String[] args) throws InterruptedException { + System.out.println("pace behavior"); + countDown = new CountDownLatch(1); + initPaceFlowRule(); + simulatePulseFlow(); + countDown.await(); + + System.out.println("done"); + System.out.println("total pass:" + pass.get() + ", total block:" + block.get()); + + System.out.println(); + System.out.println("default behavior"); + TimeUnit.SECONDS.sleep(5); + done.set(0); + pass.set(0); + block.set(0); + countDown = new CountDownLatch(1); + initDefaultFlowRule(); + simulatePulseFlow(); + countDown.await(); + System.out.println("done"); + System.out.println("total pass:" + pass.get() + ", total block:" + block.get()); + System.exit(0); + } + + private static void initPaceFlowRule() { + List
+ * ... + * 1530497805902, total:1, pass:1, block:0 // run in slow qps + * 1530497806905, total:3, pass:3, block:0 + * 1530497807909, total:2, pass:2, block:0 + * 1530497808913, total:3, pass:3, block:0 + * 1530497809917, total:269, pass:6, block:263 // request qps burst increase, warm up behavior triggered. + * 1530497810917, total:3676, pass:7, block:3669 + * 1530497811919, total:3734, pass:9, block:3725 + * 1530497812920, total:3692, pass:9, block:3683 + * 1530497813923, total:3642, pass:10, block:3632 + * 1530497814926, total:3685, pass:10, block:3675 + * 1530497815930, total:3671, pass:11, block:3660 + * 1530497816933, total:3660, pass:15, block:3645 + * 1530497817936, total:3681, pass:21, block:3661 // warm up process end, pass qps increased to {@link com.alibaba.csp.sentinel.slots.block.flow.FlowRule#count} + * 1530497818940, total:3737, pass:20, block:3716 + * 1530497819945, total:3663, pass:20, block:3643 + * 1530497820950, total:3723, pass:21, block:3702 + * 1530497821954, total:3680, pass:20, block:3660 + * ... + *+ * + * @author jialiang.linjl + */ +public class WarmUpFlowDemo { + + private static final String KEY = "abc"; + + private static AtomicInteger pass = new AtomicInteger(); + private static AtomicInteger block = new AtomicInteger(); + private static AtomicInteger total = new AtomicInteger(); + + private static volatile boolean stop = false; + + private static final int threadCount = 100; + private static int seconds = 60 + 40; + + public static void main(String[] args) throws Exception { + initFlowRule(); + // trigger Sentinel internal init + Entry entry = null; + try { + entry = SphU.entry(KEY); + } catch (Exception e) { + } finally { + if (entry != null) { + entry.exit(); + } + } + + Thread timer = new Thread(new TimerTask()); + timer.setName("sentinel-timer-task"); + timer.start(); + + //first make the system run on a very low condition + for (int i = 0; i < 3; i++) { + Thread t = new Thread(new WarmUpTask()); + t.setName("sentinel-warmup-task"); + t.start(); + } + Thread.sleep(20000); + + /* + * Start more thread to simulate more qps. Since we use {@link RuleConstant.CONTROL_BEHAVIOR_WARM_UP} as + * {@link FlowRule#controlBehavior}, real passed qps will increase to {@link FlowRule#count} in + * {@link FlowRule#warmUpPeriodSec} seconds. + */ + for (int i = 0; i < threadCount; i++) { + Thread t = new Thread(new RunTask()); + t.setName("sentinel-run-task"); + t.start(); + } + } + + private static void initFlowRule() { + List
+ * In short, {@link com.alibaba.csp.sentinel.slots.block.RuleConstant#CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER} behaves like + * {@link com.alibaba.csp.sentinel.slots.block.RuleConstant#CONTROL_BEHAVIOR_WARM_UP} + {@link com.alibaba.csp.sentinel.slots.block.RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER}. + *
+ * + * + * Run this demo, results are as follows: + *+ * ... + * 1541035848056, total:5, pass:5, block:0 // run in slow qps + * 1541035849061, total:0, pass:0, block:0 + * 1541035850066, total:6, pass:6, block:0 + * 1541035851068, total:2, pass:2, block:0 + * 1541035852073, total:3, pass:3, block:0 + * 1541035853078, total:3361, pass:7, block:3354 // request qps burst increase, warm up behavior triggered. + * 1541035854083, total:3414, pass:7, block:3407 + * 1541035855087, total:3377, pass:7, block:3370 + * 1541035856091, total:3366, pass:8, block:3358 + * 1541035857096, total:3259, pass:8, block:3251 + * 1541035858101, total:3066, pass:13, block:3054 + * 1541035859105, total:3042, pass:15, block:3026 + * 1541035860109, total:2946, pass:17, block:2929 + * 1541035861113, total:2909, pass:20, block:2889 // warm up process end, pass qps increased to {@link com.alibaba.csp.sentinel.slots.block.flow.FlowRule#count} + * 1541035862117, total:2970, pass:20, block:2950 + * 1541035863122, total:2919, pass:20, block:2899 + * 1541035864127, total:2903, pass:21, block:2882 + * 1541035865133, total:2930, pass:20, block:2910 + * ... + *+ * + * @author CarpenterLee + * @see WarmUpFlowDemo + * @see PaceFlowDemo + */ +public class WarmUpRateLimiterFlowDemo { + private static final String KEY = "abc"; + + private static AtomicInteger pass = new AtomicInteger(); + private static AtomicInteger block = new AtomicInteger(); + private static AtomicInteger total = new AtomicInteger(); + + private static volatile boolean stop = false; + + private static final int threadCount = 100; + private static int seconds = 100; + + public static void main(String[] args) throws Exception { + initFlowRule(); + // trigger Sentinel internal init + Entry entry = null; + try { + entry = SphU.entry(KEY); + } catch (Exception e) { + } finally { + if (entry != null) { + entry.exit(); + } + } + + Thread timer = new Thread(new TimerTask()); + timer.setName("sentinel-timer-task"); + timer.start(); + + //first make the system run on a very low condition + for (int i = 0; i < 3; i++) { + Thread t = new Thread(new SlowTask()); + t.setName("sentinel-slow-task"); + t.start(); + } + Thread.sleep(5000); + + // request qps burst increase, warm up behavior triggered. + for (int i = 0; i < threadCount; i++) { + Thread t = new Thread(new RunTask()); + t.setName("sentinel-run-task"); + t.start(); + } + } + + private static void initFlowRule() { + List