Make the value of RT_MAX_EXCEED_N in DegradeRule configurable (#789)

- Add two attributes in DegradeRule: rtSlowRequestAmount and minRequestAmount
This commit is contained in:
Lin.Liang 2019-06-14 17:42:03 +08:00 committed by Eric Zhao
parent e6e27c6faa
commit 2eecd3ac6a
4 changed files with 133 additions and 38 deletions

View File

@ -36,6 +36,10 @@ public final class RuleConstant {
*/ */
public static final int DEGRADE_GRADE_EXCEPTION_COUNT = 2; 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 AUTHORITY_WHITE = 0; public static final int AUTHORITY_WHITE = 0;
public static final int AUTHORITY_BLACK = 1; public static final int AUTHORITY_BLACK = 1;

View File

@ -15,12 +15,6 @@
*/ */
package com.alibaba.csp.sentinel.slots.block.degrade; package com.alibaba.csp.sentinel.slots.block.degrade;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory; import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.context.Context; import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.ClusterNode; import com.alibaba.csp.sentinel.node.ClusterNode;
@ -29,6 +23,12 @@ import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* <p> * <p>
* Degrade is used when the resources are in an unstable state, these resources * Degrade is used when the resources are in an unstable state, these resources
@ -55,7 +55,15 @@ import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
*/ */
public class DegradeRule extends AbstractRule { public class DegradeRule extends AbstractRule {
private static final int RT_MAX_EXCEED_N = 5; /**
* 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") @SuppressWarnings("PMD.ThreadPoolCreationRule")
private static ScheduledExecutorService pool = Executors.newScheduledThreadPool( private static ScheduledExecutorService pool = Executors.newScheduledThreadPool(
@ -137,7 +145,7 @@ public class DegradeRule extends AbstractRule {
return false; return false;
} }
DegradeRule that = (DegradeRule)o; DegradeRule that = (DegradeRule) o;
if (count != that.count) { if (count != that.count) {
return false; return false;
@ -148,6 +156,13 @@ public class DegradeRule extends AbstractRule {
if (grade != that.grade) { if (grade != that.grade) {
return false; return false;
} }
if (rtSlowRequestAmount != that.rtSlowRequestAmount) {
return false;
}
if (minRequestAmount != that.minRequestAmount) {
return false;
}
return true; return true;
} }
@ -157,6 +172,8 @@ public class DegradeRule extends AbstractRule {
result = 31 * result + new Double(count).hashCode(); result = 31 * result + new Double(count).hashCode();
result = 31 * result + timeWindow; result = 31 * result + timeWindow;
result = 31 * result + grade; result = 31 * result + grade;
result = 31 * result + rtSlowRequestAmount;
result = 31 * result + minRequestAmount;
return result; return result;
} }
@ -179,20 +196,21 @@ public class DegradeRule extends AbstractRule {
} }
// Sentinel will degrade the service only if count exceeds. // Sentinel will degrade the service only if count exceeds.
if (passCount.incrementAndGet() < RT_MAX_EXCEED_N) { if (passCount.incrementAndGet() < rtSlowRequestAmount) {
return true; return true;
} }
} else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) { } else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
double exception = clusterNode.exceptionQps(); double exception = clusterNode.exceptionQps();
double success = clusterNode.successQps(); double success = clusterNode.successQps();
double total = clusterNode.totalQps(); double total = clusterNode.totalQps();
// if total qps less than RT_MAX_EXCEED_N, pass. // if total qps less than minRequestAmount, pass.
if (total < RT_MAX_EXCEED_N) { if (total < minRequestAmount) {
return true; return true;
} }
//in the same aligned statistic time window, success (aka. completed count) = exception count + non-exception count (realSuccess)
double realSuccess = success - exception; double realSuccess = success - exception;
if (realSuccess <= 0 && exception < RT_MAX_EXCEED_N) { if (realSuccess <= 0 && exception < minRequestAmount) {
return true; return true;
} }
@ -214,17 +232,37 @@ public class DegradeRule extends AbstractRule {
return false; return false;
} }
@Override @Override
public String toString() { public String toString() {
return "DegradeRule{" + return "DegradeRule{" +
"resource=" + getResource() + "resource=" + getResource() +
", grade=" + grade + ", grade=" + grade +
", count=" + count + ", count=" + count +
", limitApp=" + getLimitApp() + ", limitApp=" + getLimitApp() +
", timeWindow=" + timeWindow + ", 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 static final class ResetTask implements Runnable {
private DegradeRule rule; private DegradeRule rule;

View File

@ -15,14 +15,6 @@
*/ */
package com.alibaba.csp.sentinel.slots.block.degrade; package com.alibaba.csp.sentinel.slots.block.degrade;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.context.Context; import com.alibaba.csp.sentinel.context.Context;
import com.alibaba.csp.sentinel.node.ClusterNode; import com.alibaba.csp.sentinel.node.ClusterNode;
@ -30,6 +22,14 @@ import com.alibaba.csp.sentinel.node.DefaultNode;
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper; import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/** /**
* @author jialiang.linjl * @author jialiang.linjl
@ -47,12 +47,16 @@ public class DegradeTest {
when(node.getClusterNode()).thenReturn(cn); when(node.getClusterNode()).thenReturn(cn);
when(cn.avgRt()).thenReturn(2d); when(cn.avgRt()).thenReturn(2d);
int rtSlowRequestAmount = 10;
DegradeRule rule = new DegradeRule(); DegradeRule rule = new DegradeRule();
rule.setCount(1); rule.setCount(1);
rule.setResource(key); rule.setResource(key);
rule.setTimeWindow(2); rule.setTimeWindow(2);
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
rule.setRtSlowRequestAmount(rtSlowRequestAmount);
for (int i = 0; i < 4; i++) { //Will true
for (int i = 0; i < rtSlowRequestAmount - 1; i++) {
assertTrue(rule.passCheck(context, node, 1)); assertTrue(rule.passCheck(context, node, 1));
} }
@ -69,9 +73,6 @@ public class DegradeTest {
public void testExceptionRatioModeDegrade() throws Throwable { public void testExceptionRatioModeDegrade() throws Throwable {
String key = "test_degrade_exception_ratio"; String key = "test_degrade_exception_ratio";
ClusterNode cn = mock(ClusterNode.class); ClusterNode cn = mock(ClusterNode.class);
when(cn.exceptionQps()).thenReturn(2d);
// Indicates that there are QPS more than min threshold.
when(cn.totalQps()).thenReturn(12d);
ClusterBuilderSlot.getClusterNodeMap().put(new StringResourceWrapper(key, EntryType.IN), cn); ClusterBuilderSlot.getClusterNodeMap().put(new StringResourceWrapper(key, EntryType.IN), cn);
Context context = mock(Context.class); Context context = mock(Context.class);
@ -83,17 +84,39 @@ public class DegradeTest {
rule.setResource(key); rule.setResource(key);
rule.setTimeWindow(2); rule.setTimeWindow(2);
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
rule.setMinRequestAmount(20);
// Will true. While totalQps < minRequestAmount
when(cn.totalQps()).thenReturn(8d);
assertTrue(rule.passCheck(context, node, 1));
// Will true.
when(cn.totalQps()).thenReturn(21d);
when(cn.successQps()).thenReturn(9d);
when(cn.exceptionQps()).thenReturn(9d);
assertTrue(rule.passCheck(context, node, 1));
// Will true. While totalQps > minRequestAmount and exceptionRation < count
when(cn.totalQps()).thenReturn(100d);
when(cn.successQps()).thenReturn(90d);
when(cn.exceptionQps()).thenReturn(10d);
assertTrue(rule.passCheck(context, node, 1));
// Will fail. While totalQps > minRequestAmount and exceptionRation > count
rule.setMinRequestAmount(5);
when(cn.totalQps()).thenReturn(12d);
when(cn.successQps()).thenReturn(8d); when(cn.successQps()).thenReturn(8d);
when(cn.exceptionQps()).thenReturn(6d);
// Will fail.
assertFalse(rule.passCheck(context, node, 1)); assertFalse(rule.passCheck(context, node, 1));
// Restore from the degrade timeout. // Restore from the degrade timeout.
TimeUnit.MILLISECONDS.sleep(2200); TimeUnit.MILLISECONDS.sleep(2200);
when(cn.successQps()).thenReturn(20d);
// Will pass. // Will pass.
when(cn.totalQps()).thenReturn(106d);
when(cn.successQps()).thenReturn(100d);
assertTrue(rule.passCheck(context, node, 1)); assertTrue(rule.passCheck(context, node, 1));
} }
@ -127,4 +150,33 @@ public class DegradeTest {
assertTrue(rule.passCheck(context, node, 1)); assertTrue(rule.passCheck(context, node, 1));
} }
@Test
public void testEquals() {
DegradeRule degradeRule1 = new DegradeRule();
DegradeRule degradeRule2 = new DegradeRule();
assertTrue(degradeRule1.equals(degradeRule2));
int rtSlowRequestAmount = 10;
int minRequestAmount = 20;
double count = 1.0;
int timeWindow = 2;
degradeRule1.setRtSlowRequestAmount(rtSlowRequestAmount);
degradeRule1.setMinRequestAmount(minRequestAmount);
degradeRule1.setCount(count);
degradeRule1.setTimeWindow(timeWindow);
degradeRule1.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule2.setRtSlowRequestAmount(rtSlowRequestAmount);
degradeRule2.setMinRequestAmount(minRequestAmount);
degradeRule2.setCount(count);
degradeRule2.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule2.setTimeWindow(timeWindow);
assertTrue(degradeRule1.equals(degradeRule2));
degradeRule2.setMinRequestAmount(100);
assertFalse(degradeRule1.equals(degradeRule2));
}
} }

View File

@ -15,11 +15,6 @@
*/ */
package com.alibaba.csp.sentinel.demo.degrade; 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.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;
@ -29,6 +24,11 @@ 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.util.TimeUtil; import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/** /**
* <p> * <p>
* Degrade is used when the resources are in an unstable state, these resources * Degrade is used when the resources are in an unstable state, these resources
@ -115,6 +115,7 @@ public class ExceptionRatioDegradeDemo {
rule.setCount(0.1); rule.setCount(0.1);
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
rule.setTimeWindow(10); rule.setTimeWindow(10);
rule.setMinRequestAmount(20);
rules.add(rule); rules.add(rule);
DegradeRuleManager.loadRules(rules); DegradeRuleManager.loadRules(rules);
} }