Refine the DegradeRule and add validating logic for the two new attributes

- improvement of #789

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
Eric Zhao 2019-06-17 20:38:02 +08:00
parent 254ccbbdc5
commit 00f116e344
4 changed files with 89 additions and 99 deletions

View File

@ -36,9 +36,8 @@ public final class RuleConstant {
*/
public static final int DEGRADE_GRADE_EXCEPTION_COUNT = 2;
public static final int DEGRADE_GRADE_RT_MAX_EXCEED_N = 5;
public static final int DEGRADE_GRADE_MIN_REQUEST_EXCEED_N = 5;
public static final int DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT = 5;
public static final int DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT = 5;
public static final int AUTHORITY_WHITE = 0;
public static final int AUTHORITY_BLACK = 1;

View File

@ -55,16 +55,6 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public class DegradeRule extends AbstractRule {
/**
* minimum number of consecutive slow requests that can trigger RT circuit breaking
*/
private int rtSlowRequestAmount = RuleConstant.DEGRADE_GRADE_RT_MAX_EXCEED_N;
/**
* minimum number of requests (in an active statistic time span) that can trigger circuit breaking
*/
private int minRequestAmount = RuleConstant.DEGRADE_GRADE_MIN_REQUEST_EXCEED_N;
@SuppressWarnings("PMD.ThreadPoolCreationRule")
private static ScheduledExecutorService pool = Executors.newScheduledThreadPool(
Runtime.getRuntime().availableProcessors(), new NamedThreadFactory("sentinel-degrade-reset-task", true));
@ -86,11 +76,23 @@ public class DegradeRule extends AbstractRule {
private int timeWindow;
/**
* Degrade strategy (0: average RT, 1: exception ratio).
* Degrade strategy (0: average RT, 1: exception ratio, 2: exception count).
*/
private int grade = RuleConstant.DEGRADE_GRADE_RT;
private final AtomicBoolean cut = new AtomicBoolean(false);
/**
* Minimum number of consecutive slow requests that can trigger RT circuit breaking.
*
* @since 1.7.0
*/
private int rtSlowRequestAmount = RuleConstant.DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT;
/**
* Minimum number of requests (in an active statistic time span) that can trigger circuit breaking.
*
* @since 1.7.0
*/
private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;
public int getGrade() {
return grade;
@ -101,8 +103,6 @@ public class DegradeRule extends AbstractRule {
return this;
}
private AtomicLong passCount = new AtomicLong(0);
public double getCount() {
return count;
}
@ -112,18 +112,6 @@ public class DegradeRule extends AbstractRule {
return this;
}
private boolean isCut() {
return cut.get();
}
private void setCut(boolean cut) {
this.cut.set(cut);
}
public AtomicLong getPassCount() {
return passCount;
}
public int getTimeWindow() {
return timeWindow;
}
@ -133,37 +121,35 @@ public class DegradeRule extends AbstractRule {
return this;
}
public int getRtSlowRequestAmount() {
return rtSlowRequestAmount;
}
public DegradeRule setRtSlowRequestAmount(int rtSlowRequestAmount) {
this.rtSlowRequestAmount = rtSlowRequestAmount;
return this;
}
public int getMinRequestAmount() {
return minRequestAmount;
}
public DegradeRule setMinRequestAmount(int minRequestAmount) {
this.minRequestAmount = minRequestAmount;
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DegradeRule)) {
return false;
}
if (!super.equals(o)) {
return false;
}
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
if (!super.equals(o)) { return false; }
DegradeRule that = (DegradeRule) o;
if (count != that.count) {
return false;
}
if (timeWindow != that.timeWindow) {
return false;
}
if (grade != that.grade) {
return false;
}
if (rtSlowRequestAmount != that.rtSlowRequestAmount) {
return false;
}
if (minRequestAmount != that.minRequestAmount) {
return false;
}
return true;
return Double.compare(that.count, count) == 0 &&
timeWindow == that.timeWindow &&
grade == that.grade &&
rtSlowRequestAmount == that.rtSlowRequestAmount &&
minRequestAmount == that.minRequestAmount;
}
@Override
@ -177,6 +163,24 @@ public class DegradeRule extends AbstractRule {
return result;
}
@Override
public String toString() {
return "DegradeRule{" +
"resource=" + getResource() +
", grade=" + grade +
", count=" + count +
", limitApp=" + getLimitApp() +
", timeWindow=" + timeWindow +
", rtSlowRequestAmount=" + rtSlowRequestAmount +
", minRequestAmount=" + minRequestAmount +
"}";
}
// Internal implementation (will be deprecated and moved outside).
private AtomicLong passCount = new AtomicLong(0);
private final AtomicBoolean cut = new AtomicBoolean(false);
@Override
public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
if (cut.get()) {
@ -203,12 +207,13 @@ public class DegradeRule extends AbstractRule {
double exception = clusterNode.exceptionQps();
double success = clusterNode.successQps();
double total = clusterNode.totalQps();
// if total qps less than minRequestAmount, pass.
// If total amount is less than minRequestAmount, the request will pass.
if (total < minRequestAmount) {
return true;
}
//in the same aligned statistic time window, success (aka. completed count) = exception count + non-exception count (realSuccess)
// In the same aligned statistic time window,
// "success" (aka. completed count) = exception count + non-exception count (realSuccess)
double realSuccess = success - exception;
if (realSuccess <= 0 && exception < minRequestAmount) {
return true;
@ -232,37 +237,6 @@ public class DegradeRule extends AbstractRule {
return false;
}
@Override
public String toString() {
return "DegradeRule{" +
"resource=" + getResource() +
", grade=" + grade +
", count=" + count +
", limitApp=" + getLimitApp() +
", timeWindow=" + timeWindow +
", rtSlowRequestAmount=" + rtSlowRequestAmount +
", minRequestAmount=" + minRequestAmount +
"}";
}
public int getRtSlowRequestAmount() {
return rtSlowRequestAmount;
}
public void setRtSlowRequestAmount(int rtSlowRequestAmount) {
this.rtSlowRequestAmount = rtSlowRequestAmount;
}
public int getMinRequestAmount() {
return minRequestAmount;
}
public void setMinRequestAmount(int minRequestAmount) {
this.minRequestAmount = minRequestAmount;
}
private static final class ResetTask implements Runnable {
private DegradeRule rule;
@ -273,9 +247,8 @@ public class DegradeRule extends AbstractRule {
@Override
public void run() {
rule.getPassCount().set(0);
rule.passCount.set(0);
rule.cut.set(false);
}
}
}

View File

@ -211,16 +211,22 @@ public final class DegradeRuleManager {
if (!baseValid) {
return false;
}
// Warn for RT mode that exceeds the {@code TIME_DROP_VALVE}.
int maxAllowedRt = Constants.TIME_DROP_VALVE;
if (rule.getGrade() == RuleConstant.DEGRADE_GRADE_RT && rule.getCount() > maxAllowedRt) {
RecordLog.warn(String.format("[DegradeRuleManager] WARN: setting large RT threshold (%.1f ms) in RT mode"
+ " will not take effect since it exceeds the max allowed value (%d ms)", rule.getCount(),
maxAllowedRt));
if (rule.getGrade() == RuleConstant.DEGRADE_GRADE_RT) {
if (rule.getRtSlowRequestAmount() <= 0) {
return false;
}
// Warn for RT mode that exceeds the {@code TIME_DROP_VALVE}.
if (rule.getCount() > maxAllowedRt) {
RecordLog.warn(String.format("[DegradeRuleManager] WARN: setting large RT threshold (%.1f ms)"
+ " in RT mode will not take effect since it exceeds the max allowed value (%d ms)",
rule.getCount(), maxAllowedRt));
}
}
// Check exception ratio mode.
if (rule.getGrade() == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO && rule.getCount() > 1) {
return false;
if (rule.getGrade() == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
return rule.getCount() <= 1 && rule.getMinRequestAmount() > 0;
}
return true;
}

View File

@ -43,11 +43,23 @@ public class DegradeRuleManagerTest {
.setCount(-3)
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
.setTimeWindow(2);
DegradeRule rule5 = new DegradeRule("Sentinel")
.setCount(97)
.setGrade(RuleConstant.DEGRADE_GRADE_RT)
.setTimeWindow(15)
.setRtSlowRequestAmount(0);
DegradeRule rule6 = new DegradeRule("Sentinel")
.setCount(0.93d)
.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
.setTimeWindow(20)
.setMinRequestAmount(0);
assertFalse(DegradeRuleManager.isValidRule(rule1));
assertFalse(DegradeRuleManager.isValidRule(rule2));
assertFalse(DegradeRuleManager.isValidRule(rule3));
assertTrue(DegradeRuleManager.isValidRule(rule3.setCount(1.0d)));
assertTrue(DegradeRuleManager.isValidRule(rule3.setCount(0.0d)));
assertFalse(DegradeRuleManager.isValidRule(rule4));
assertFalse(DegradeRuleManager.isValidRule(rule5));
assertFalse(DegradeRuleManager.isValidRule(rule6));
}
}