Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -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,68 +46,87 @@ 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 = 60 + 40; | |||||
private static int seconds = 120; | |||||
public static void main(String[] args) throws Exception { | public static void main(String[] args) throws Exception { | ||||
tick(); | |||||
initDegradeRule(); | 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(); | |||||
} | |||||
registerStateChangeObserver(); | |||||
startTick(); | |||||
final int concurrency = 8; | |||||
for (int i = 0; i < concurrency; i++) { | |||||
Thread entryThread = new Thread(() -> { | |||||
while (true) { | |||||
Entry entry = null; | |||||
try { | |||||
entry = SphU.entry(KEY); | |||||
sleep(ThreadLocalRandom.current().nextInt(5, 10)); | |||||
pass.addAndGet(1); | |||||
// Error probability is 45% | |||||
if (ThreadLocalRandom.current().nextInt(0, 100) > 55) { | |||||
// biz code raise an exception. | |||||
throw new RuntimeException("oops"); | |||||
} | |||||
} catch (BlockException e) { | |||||
block.addAndGet(1); | |||||
sleep(ThreadLocalRandom.current().nextInt(5, 10)); | |||||
} catch (Throwable t) { | |||||
bizException.incrementAndGet(); | |||||
// It's required to record exception here manually. | |||||
Tracer.traceEntry(t, entry); | |||||
} finally { | |||||
total.addAndGet(1); | |||||
if (entry != null) { | |||||
entry.exit(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
}); | }); | ||||
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>(); | |||||
DegradeRule rule = new DegradeRule(); | |||||
rule.setResource(KEY); | |||||
// set limit exception ratio to 0.1 | |||||
rule.setCount(0.1); | |||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); | |||||
rule.setTimeWindow(10); | |||||
rule.setMinRequestAmount(20); | |||||
List<DegradeRule> rules = new ArrayList<>(); | |||||
DegradeRule rule = new DegradeRule(KEY) | |||||
.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType()) | |||||
// Set ratio threshold to 50%. | |||||
.setCount(0.5d) | |||||
.setStatIntervalMs(30000) | |||||
.setMinRequestAmount(50) | |||||
// 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 { | |||||
TimeUnit.SECONDS.sleep(1); | |||||
} catch (InterruptedException e) { | |||||
} | |||||
sleep(1000); | |||||
long globalTotal = total.get(); | long globalTotal = total.get(); | ||||
long oneSecondTotal = globalTotal - oldTotal; | long oneSecondTotal = globalTotal - oldTotal; | ||||
oldTotal = globalTotal; | oldTotal = globalTotal; | ||||
@@ -166,7 +170,7 @@ public class ExceptionRatioDegradeDemo { | |||||
} | } | ||||
long cost = System.currentTimeMillis() - start; | long cost = System.currentTimeMillis() - start; | ||||
System.out.println("time cost: " + cost + " ms"); | System.out.println("time cost: " + cost + " ms"); | ||||
System.out.println("total:" + total.get() + ", pass:" + pass.get() | |||||
System.out.println("total: " + total.get() + ", pass:" + pass.get() | |||||
+ ", block:" + block.get() + ", bizException:" + bizException.get()); | + ", block:" + block.get() + ", bizException:" + bizException.get()); | ||||
System.exit(0); | System.exit(0); | ||||
} | } |
@@ -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 out put 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 | |||||
* 1529399830824,total:19806, pass:0, block:19806 //begin degrade | |||||
* 1529399829825,total:19179, pass:4, block:19176 // circuit breaker opens | |||||
* 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,95 +47,114 @@ 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 | |||||
* quickly | |||||
* 1529399839829,total:14494, pass:104, block:14390 // After 10 seconds, the system restored | |||||
* 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 volatile boolean stop = false; | |||||
private static int seconds = 120; | |||||
private static AtomicInteger total = new AtomicInteger(); | |||||
private static AtomicInteger pass = new AtomicInteger(); | private static AtomicInteger pass = new AtomicInteger(); | ||||
private static AtomicInteger block = 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 { | public static void main(String[] args) throws Exception { | ||||
tick(); | |||||
initDegradeRule(); | initDegradeRule(); | ||||
for (int i = 0; i < threadCount; i++) { | |||||
Thread entryThread = new Thread(new Runnable() { | |||||
@Override | |||||
public void run() { | |||||
while (true) { | |||||
Entry entry = null; | |||||
try { | |||||
TimeUnit.MILLISECONDS.sleep(5); | |||||
entry = SphU.entry(KEY); | |||||
// token acquired | |||||
pass.incrementAndGet(); | |||||
// sleep 600 ms, as rt | |||||
TimeUnit.MILLISECONDS.sleep(600); | |||||
} catch (Exception e) { | |||||
block.incrementAndGet(); | |||||
} finally { | |||||
total.incrementAndGet(); | |||||
if (entry != null) { | |||||
entry.exit(); | |||||
} | |||||
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("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>(); | |||||
DegradeRule rule = new DegradeRule(); | |||||
rule.setResource(KEY); | |||||
// set threshold rt, 10 ms | |||||
rule.setCount(10); | |||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); | |||||
rule.setTimeWindow(10); | |||||
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); | rules.add(rule); | ||||
DegradeRuleManager.loadRules(rules); | 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 tick() { | |||||
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 { | |||||
TimeUnit.SECONDS.sleep(1); | |||||
} catch (InterruptedException e) { | |||||
} | |||||
sleep(1000); | |||||
long globalTotal = total.get(); | long globalTotal = total.get(); | ||||
long oneSecondTotal = globalTotal - oldTotal; | long oneSecondTotal = globalTotal - oldTotal; | ||||
@@ -178,10 +178,9 @@ public class RtDegradeDemo { | |||||
long cost = System.currentTimeMillis() - start; | long cost = System.currentTimeMillis() - start; | ||||
System.out.println("time cost: " + cost + " ms"); | System.out.println("time cost: " + cost + " ms"); | ||||
System.out.println("total:" + total.get() + ", pass:" + pass.get() | |||||
System.out.println("total: " + total.get() + ", pass:" + pass.get() | |||||
+ ", block:" + block.get()); | + ", block:" + block.get()); | ||||
System.exit(0); | System.exit(0); | ||||
} | } | ||||
} | } | ||||
} | } |