Update demo for circuit breaking (DegradeRule)
Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
07b811196b
commit
19db20f00d
|
|
@ -1,169 +0,0 @@
|
||||||
package com.alibaba.csp.sentinel.demo.degrade;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.Entry;
|
|
||||||
import com.alibaba.csp.sentinel.SphU;
|
|
||||||
import com.alibaba.csp.sentinel.Tracer;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
|
||||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Degrade is used when the resources are in an unstable state, these resources
|
|
||||||
* will be degraded within the next defined time window. There are three ways to
|
|
||||||
* measure whether a resource is stable or not:
|
|
||||||
* <ul>
|
|
||||||
* <li>
|
|
||||||
* Exception count: When the exception count in the last 60 seconds greats than
|
|
||||||
* or equals to the threshold, access to the resource will be blocked in the
|
|
||||||
* coming time window.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* Exception ratio, see {@link ExceptionRatioDegradeDemo}.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* For average response time, see {@link RtDegradeDemo}.
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* Note: When degrading by {@link RuleConstant#DEGRADE_GRADE_EXCEPTION_COUNT}, time window
|
|
||||||
* less than 60 seconds will not work as expected. Because the exception count is
|
|
||||||
* summed by minute, when a short time window elapsed, the degradation condition
|
|
||||||
* may still be satisfied.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Carpenter Lee
|
|
||||||
*/
|
|
||||||
public class ExceptionCountDegradeDemo {
|
|
||||||
private static final String KEY = "abc";
|
|
||||||
|
|
||||||
private static AtomicInteger total = new AtomicInteger();
|
|
||||||
private static AtomicInteger pass = new AtomicInteger();
|
|
||||||
private static AtomicInteger block = new AtomicInteger();
|
|
||||||
private static AtomicInteger bizException = new AtomicInteger();
|
|
||||||
|
|
||||||
private static volatile boolean stop = false;
|
|
||||||
private static final int threadCount = 1;
|
|
||||||
private static int seconds = 60 + 40;
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
tick();
|
|
||||||
initDegradeRule();
|
|
||||||
|
|
||||||
for (int i = 0; i < threadCount; i++) {
|
|
||||||
Thread entryThread = new Thread(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
int count = 0;
|
|
||||||
while (true) {
|
|
||||||
count++;
|
|
||||||
Entry entry = null;
|
|
||||||
try {
|
|
||||||
Thread.sleep(20);
|
|
||||||
entry = SphU.entry(KEY);
|
|
||||||
// token acquired, means pass
|
|
||||||
pass.addAndGet(1);
|
|
||||||
if (count % 2 == 0) {
|
|
||||||
// biz code raise an exception.
|
|
||||||
throw new RuntimeException("throw runtime ");
|
|
||||||
}
|
|
||||||
} catch (BlockException e) {
|
|
||||||
block.addAndGet(1);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
bizException.incrementAndGet();
|
|
||||||
Tracer.trace(t);
|
|
||||||
} finally {
|
|
||||||
total.addAndGet(1);
|
|
||||||
if (entry != null) {
|
|
||||||
entry.exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
entryThread.setName("working-thread");
|
|
||||||
entryThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initDegradeRule() {
|
|
||||||
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
|
||||||
DegradeRule rule = new DegradeRule();
|
|
||||||
rule.setResource(KEY);
|
|
||||||
// set limit exception count to 4
|
|
||||||
rule.setCount(4);
|
|
||||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
|
|
||||||
/**
|
|
||||||
* When degrading by {@link RuleConstant#DEGRADE_GRADE_EXCEPTION_COUNT}, time window
|
|
||||||
* less than 60 seconds will not work as expected. Because the exception count is
|
|
||||||
* summed by minute, when a short time window elapsed, the degradation condition
|
|
||||||
* may still be satisfied.
|
|
||||||
*/
|
|
||||||
rule.setTimeWindow(10);
|
|
||||||
rules.add(rule);
|
|
||||||
DegradeRuleManager.loadRules(rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void tick() {
|
|
||||||
Thread timer = new Thread(new TimerTask());
|
|
||||||
timer.setName("sentinel-timer-task");
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TimerTask implements Runnable {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
System.out.println("begin to statistic!!!");
|
|
||||||
long oldTotal = 0;
|
|
||||||
long oldPass = 0;
|
|
||||||
long oldBlock = 0;
|
|
||||||
long oldBizException = 0;
|
|
||||||
while (!stop) {
|
|
||||||
try {
|
|
||||||
TimeUnit.SECONDS.sleep(1);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
long globalTotal = total.get();
|
|
||||||
long oneSecondTotal = globalTotal - oldTotal;
|
|
||||||
oldTotal = globalTotal;
|
|
||||||
|
|
||||||
long globalPass = pass.get();
|
|
||||||
long oneSecondPass = globalPass - oldPass;
|
|
||||||
oldPass = globalPass;
|
|
||||||
|
|
||||||
long globalBlock = block.get();
|
|
||||||
long oneSecondBlock = globalBlock - oldBlock;
|
|
||||||
oldBlock = globalBlock;
|
|
||||||
|
|
||||||
long globalBizException = bizException.get();
|
|
||||||
long oneSecondBizException = globalBizException - oldBizException;
|
|
||||||
oldBizException = globalBizException;
|
|
||||||
|
|
||||||
System.out.println(TimeUtil.currentTimeMillis() + ", oneSecondTotal:" + oneSecondTotal
|
|
||||||
+ ", oneSecondPass:" + oneSecondPass
|
|
||||||
+ ", oneSecondBlock:" + oneSecondBlock
|
|
||||||
+ ", oneSecondBizException:" + oneSecondBizException);
|
|
||||||
if (seconds-- <= 0) {
|
|
||||||
stop = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
long cost = System.currentTimeMillis() - start;
|
|
||||||
System.out.println("time cost: " + cost + " ms");
|
|
||||||
System.out.println("total:" + total.get() + ", pass:" + pass.get()
|
|
||||||
+ ", block:" + block.get() + ", bizException:" + bizException.get());
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,41 +19,26 @@ import com.alibaba.csp.sentinel.Entry;
|
||||||
import com.alibaba.csp.sentinel.SphU;
|
import com.alibaba.csp.sentinel.SphU;
|
||||||
import com.alibaba.csp.sentinel.Tracer;
|
import com.alibaba.csp.sentinel.Tracer;
|
||||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker.State;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
|
||||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
|
||||||
* Degrade is used when the resources are in an unstable state, these resources
|
|
||||||
* will be degraded within the next defined time window. There are three ways to
|
|
||||||
* measure whether a resource is stable or not:
|
|
||||||
* <ul>
|
|
||||||
* <li>
|
|
||||||
* Exception ratio: When the ratio of exception count per second and the success
|
|
||||||
* qps greats than or equals to the threshold, access to the resource will be blocked
|
|
||||||
* in the coming time window.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* Exception Count, see {@link ExceptionCountDegradeDemo}.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* For average response time, see {@link RtDegradeDemo}.
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author jialiang.linjl
|
* @author jialiang.linjl
|
||||||
|
* @author Eric Zhao
|
||||||
*/
|
*/
|
||||||
public class ExceptionRatioDegradeDemo {
|
public class ExceptionRatioCircuitBreakerDemo {
|
||||||
|
|
||||||
private static final String KEY = "abc";
|
private static final String KEY = "some_service";
|
||||||
|
|
||||||
private static AtomicInteger total = new AtomicInteger();
|
private static AtomicInteger total = new AtomicInteger();
|
||||||
private static AtomicInteger pass = new AtomicInteger();
|
private static AtomicInteger pass = new AtomicInteger();
|
||||||
|
|
@ -61,36 +46,35 @@ public class ExceptionRatioDegradeDemo {
|
||||||
private static AtomicInteger bizException = new AtomicInteger();
|
private static AtomicInteger bizException = new AtomicInteger();
|
||||||
|
|
||||||
private static volatile boolean stop = false;
|
private static volatile boolean stop = false;
|
||||||
private static final int threadCount = 1;
|
private static int seconds = 120;
|
||||||
private static int seconds = 60 + 40;
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
tick();
|
|
||||||
initDegradeRule();
|
initDegradeRule();
|
||||||
|
registerStateChangeObserver();
|
||||||
|
startTick();
|
||||||
|
|
||||||
for (int i = 0; i < threadCount; i++) {
|
final int concurrency = 8;
|
||||||
Thread entryThread = new Thread(new Runnable() {
|
for (int i = 0; i < concurrency; i++) {
|
||||||
|
Thread entryThread = new Thread(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
int count = 0;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
count++;
|
|
||||||
Entry entry = null;
|
Entry entry = null;
|
||||||
try {
|
try {
|
||||||
Thread.sleep(20);
|
|
||||||
entry = SphU.entry(KEY);
|
entry = SphU.entry(KEY);
|
||||||
// token acquired, means pass
|
sleep(ThreadLocalRandom.current().nextInt(5, 10));
|
||||||
pass.addAndGet(1);
|
pass.addAndGet(1);
|
||||||
if (count % 2 == 0) {
|
|
||||||
|
// Error probability is 45%
|
||||||
|
if (ThreadLocalRandom.current().nextInt(0, 100) > 55) {
|
||||||
// biz code raise an exception.
|
// biz code raise an exception.
|
||||||
throw new RuntimeException("throw runtime ");
|
throw new RuntimeException("oops");
|
||||||
}
|
}
|
||||||
} catch (BlockException e) {
|
} catch (BlockException e) {
|
||||||
block.addAndGet(1);
|
block.addAndGet(1);
|
||||||
|
sleep(ThreadLocalRandom.current().nextInt(5, 10));
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
bizException.incrementAndGet();
|
bizException.incrementAndGet();
|
||||||
Tracer.trace(t);
|
// It's required to record exception here manually.
|
||||||
|
Tracer.traceEntry(t, entry);
|
||||||
} finally {
|
} finally {
|
||||||
total.addAndGet(1);
|
total.addAndGet(1);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
|
|
@ -98,31 +82,51 @@ public class ExceptionRatioDegradeDemo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
entryThread.setName("working-thread");
|
entryThread.setName("sentinel-simulate-traffic-task-" + i);
|
||||||
entryThread.start();
|
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() {
|
private static void initDegradeRule() {
|
||||||
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
List<DegradeRule> rules = new ArrayList<>();
|
||||||
DegradeRule rule = new DegradeRule();
|
DegradeRule rule = new DegradeRule(KEY)
|
||||||
rule.setResource(KEY);
|
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
|
||||||
// set limit exception ratio to 0.1
|
// Set ratio threshold to 50%.
|
||||||
rule.setCount(0.1);
|
.setCount(0.5d)
|
||||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
|
.setStatIntervalMs(30000)
|
||||||
rule.setTimeWindow(10);
|
.setMinRequestAmount(50)
|
||||||
rule.setMinRequestAmount(20);
|
// Retry timeout (in second)
|
||||||
|
.setTimeWindow(10);
|
||||||
rules.add(rule);
|
rules.add(rule);
|
||||||
DegradeRuleManager.loadRules(rules);
|
DegradeRuleManager.loadRules(rules);
|
||||||
|
System.out.println("Degrade rule loaded: " + rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void tick() {
|
private static void sleep(int timeMs) {
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(timeMs);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void startTick() {
|
||||||
Thread timer = new Thread(new TimerTask());
|
Thread timer = new Thread(new TimerTask());
|
||||||
timer.setName("sentinel-timer-task");
|
timer.setName("sentinel-timer-tick-task");
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,16 +134,16 @@ public class ExceptionRatioDegradeDemo {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
System.out.println("begin to statistic!!!");
|
System.out.println("Begin to run! Go go go!");
|
||||||
|
System.out.println("See corresponding metrics.log for accurate statistic data");
|
||||||
|
|
||||||
long oldTotal = 0;
|
long oldTotal = 0;
|
||||||
long oldPass = 0;
|
long oldPass = 0;
|
||||||
long oldBlock = 0;
|
long oldBlock = 0;
|
||||||
long oldBizException = 0;
|
long oldBizException = 0;
|
||||||
while (!stop) {
|
while (!stop) {
|
||||||
try {
|
sleep(1000);
|
||||||
TimeUnit.SECONDS.sleep(1);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
long globalTotal = total.get();
|
long globalTotal = total.get();
|
||||||
long oneSecondTotal = globalTotal - oldTotal;
|
long oneSecondTotal = globalTotal - oldTotal;
|
||||||
oldTotal = globalTotal;
|
oldTotal = globalTotal;
|
||||||
|
|
@ -17,47 +17,28 @@ package com.alibaba.csp.sentinel.demo.degrade;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.util.TimeUtil;
|
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreaker.State;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
|
||||||
import com.alibaba.csp.sentinel.Entry;
|
import com.alibaba.csp.sentinel.Entry;
|
||||||
import com.alibaba.csp.sentinel.SphU;
|
import com.alibaba.csp.sentinel.SphU;
|
||||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.EventObserverRegistry;
|
||||||
|
import com.alibaba.csp.sentinel.util.TimeUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
|
||||||
* Degrade is used when the resources are in an unstable state, these resources
|
|
||||||
* will be degraded within the next defined time window. There are two ways to
|
|
||||||
* measure whether a resource is stable or not:
|
|
||||||
* <ul>
|
|
||||||
* <li>
|
|
||||||
* Average Response Time ('DegradeRule.Grade=RuleContants.DEGRADE_GRADE_RT'): When the
|
|
||||||
* average RT greats than or equals to the threshold ('count' in 'DegradeRule', ms), the
|
|
||||||
* resource enters a quasi-degraded state. If the RT of next coming five requests still
|
|
||||||
* exceed this threshold, this resource will be downgraded, which means that in
|
|
||||||
* the next time window(Defined in 'timeWindow', s units) all the access to this
|
|
||||||
* resource will be blocked.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* Exception ratio, see {@link ExceptionRatioDegradeDemo}.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* Exception Count, see {@link ExceptionCountDegradeDemo}.
|
|
||||||
* </li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* Run this demo, and the output will be like:
|
* Run this demo, and the output will be like:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* 1529399827825,total:0, pass:0, block:0
|
* 1529399827825,total:0, pass:0, block:0
|
||||||
* 1529399828825,total:4263, pass:100, block:4164
|
* 1529399828825,total:4263, pass:100, block:4164
|
||||||
* 1529399829825,total:19179, pass:4, block:19176
|
* 1529399829825,total:19179, pass:4, block:19176 // circuit breaker opens
|
||||||
* 1529399830824,total:19806, pass:0, block:19806 //begin degrade
|
* 1529399830824,total:19806, pass:0, block:19806
|
||||||
* 1529399831825,total:19198, pass:0, block:19198
|
* 1529399831825,total:19198, pass:0, block:19198
|
||||||
* 1529399832824,total:19481, pass:0, block:19481
|
* 1529399832824,total:19481, pass:0, block:19481
|
||||||
* 1529399833826,total:19241, pass:0, block:19241
|
* 1529399833826,total:19241, pass:0, block:19241
|
||||||
|
|
@ -66,47 +47,43 @@ import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||||
* 1529399836826,total:19490, pass:0, block:19492
|
* 1529399836826,total:19490, pass:0, block:19492
|
||||||
* 1529399837828,total:19355, pass:0, block:19355
|
* 1529399837828,total:19355, pass:0, block:19355
|
||||||
* 1529399838827,total:11388, pass:0, block:11388
|
* 1529399838827,total:11388, pass:0, block:11388
|
||||||
* 1529399839829,total:14494, pass:104, block:14390 //After 10 seconds, the system is restored, and degraded very
|
* 1529399839829,total:14494, pass:104, block:14390 // After 10 seconds, the system restored
|
||||||
* quickly
|
|
||||||
* 1529399840854,total:18505, pass:0, block:18505
|
* 1529399840854,total:18505, pass:0, block:18505
|
||||||
* 1529399841854,total:19673, pass:0, block:19676
|
* 1529399841854,total:19673, pass:0, block:19676
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author jialiang.linjl
|
* @author jialiang.linjl
|
||||||
|
* @author Eric Zhao
|
||||||
*/
|
*/
|
||||||
public class RtDegradeDemo {
|
public class SlowRatioCircuitBreakerDemo {
|
||||||
|
|
||||||
private static final String KEY = "abc";
|
private static final String KEY = "some_method";
|
||||||
|
|
||||||
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 volatile boolean stop = false;
|
||||||
private static final int threadCount = 100;
|
private static int seconds = 120;
|
||||||
private static int seconds = 60 + 40;
|
|
||||||
|
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 {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
tick();
|
|
||||||
initDegradeRule();
|
initDegradeRule();
|
||||||
|
registerStateChangeObserver();
|
||||||
|
startTick();
|
||||||
|
|
||||||
for (int i = 0; i < threadCount; i++) {
|
int concurrency = 8;
|
||||||
Thread entryThread = new Thread(new Runnable() {
|
for (int i = 0; i < concurrency; i++) {
|
||||||
|
Thread entryThread = new Thread(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (true) {
|
while (true) {
|
||||||
Entry entry = null;
|
Entry entry = null;
|
||||||
try {
|
try {
|
||||||
TimeUnit.MILLISECONDS.sleep(5);
|
|
||||||
entry = SphU.entry(KEY);
|
entry = SphU.entry(KEY);
|
||||||
// token acquired
|
|
||||||
pass.incrementAndGet();
|
pass.incrementAndGet();
|
||||||
// sleep 600 ms, as rt
|
// RT: [40ms, 60ms)
|
||||||
TimeUnit.MILLISECONDS.sleep(600);
|
sleep(ThreadLocalRandom.current().nextInt(40, 60));
|
||||||
} catch (Exception e) {
|
} catch (BlockException e) {
|
||||||
block.incrementAndGet();
|
block.incrementAndGet();
|
||||||
|
sleep(ThreadLocalRandom.current().nextInt(5, 10));
|
||||||
} finally {
|
} finally {
|
||||||
total.incrementAndGet();
|
total.incrementAndGet();
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
|
|
@ -114,47 +91,70 @@ public class RtDegradeDemo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
entryThread.setName("working-thread");
|
entryThread.setName("sentinel-simulate-traffic-task-" + i);
|
||||||
entryThread.start();
|
entryThread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initDegradeRule() {
|
private static void registerStateChangeObserver() {
|
||||||
List<DegradeRule> rules = new ArrayList<DegradeRule>();
|
EventObserverRegistry.getInstance().addStateChangeObserver("logging",
|
||||||
DegradeRule rule = new DegradeRule();
|
(prevState, newState, rule, snapshotValue) -> {
|
||||||
rule.setResource(KEY);
|
if (newState == State.OPEN) {
|
||||||
// set threshold rt, 10 ms
|
System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
|
||||||
rule.setCount(10);
|
TimeUtil.currentTimeMillis(), snapshotValue));
|
||||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
|
} else {
|
||||||
rule.setTimeWindow(10);
|
System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
|
||||||
rules.add(rule);
|
TimeUtil.currentTimeMillis()));
|
||||||
DegradeRuleManager.loadRules(rules);
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void tick() {
|
private static void initDegradeRule() {
|
||||||
|
List<DegradeRule> rules = new ArrayList<>();
|
||||||
|
DegradeRule rule = new DegradeRule(KEY)
|
||||||
|
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
|
||||||
|
// Max allowed response time
|
||||||
|
.setCount(50)
|
||||||
|
// Retry timeout (in second)
|
||||||
|
.setTimeWindow(10)
|
||||||
|
// Circuit breaker opens when slow request ratio > 60%
|
||||||
|
.setSlowRatioThreshold(0.6)
|
||||||
|
.setMinRequestAmount(100)
|
||||||
|
.setStatIntervalMs(20000);
|
||||||
|
rules.add(rule);
|
||||||
|
|
||||||
|
DegradeRuleManager.loadRules(rules);
|
||||||
|
System.out.println("Degrade rule loaded: " + rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sleep(int timeMs) {
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(timeMs);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void startTick() {
|
||||||
Thread timer = new Thread(new TimerTask());
|
Thread timer = new Thread(new TimerTask());
|
||||||
timer.setName("sentinel-timer-task");
|
timer.setName("sentinel-timer-tick-task");
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TimerTask implements Runnable {
|
static class TimerTask implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
System.out.println("begin to statistic!!!");
|
System.out.println("Begin to run! Go go go!");
|
||||||
|
System.out.println("See corresponding metrics.log for accurate statistic data");
|
||||||
|
|
||||||
long oldTotal = 0;
|
long oldTotal = 0;
|
||||||
long oldPass = 0;
|
long oldPass = 0;
|
||||||
long oldBlock = 0;
|
long oldBlock = 0;
|
||||||
|
|
||||||
while (!stop) {
|
while (!stop) {
|
||||||
try {
|
sleep(1000);
|
||||||
TimeUnit.SECONDS.sleep(1);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
long globalTotal = total.get();
|
long globalTotal = total.get();
|
||||||
long oneSecondTotal = globalTotal - oldTotal;
|
long oneSecondTotal = globalTotal - oldTotal;
|
||||||
|
|
@ -183,5 +183,4 @@ public class RtDegradeDemo {
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue