- Add two attributes in DegradeRule: rtSlowRequestAmount and minRequestAmountmaster
@@ -36,6 +36,10 @@ 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 AUTHORITY_WHITE = 0; | |||
public static final int AUTHORITY_BLACK = 1; | |||
@@ -15,12 +15,6 @@ | |||
*/ | |||
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.context.Context; | |||
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.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> | |||
* 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 { | |||
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") | |||
private static ScheduledExecutorService pool = Executors.newScheduledThreadPool( | |||
@@ -137,7 +145,7 @@ public class DegradeRule extends AbstractRule { | |||
return false; | |||
} | |||
DegradeRule that = (DegradeRule)o; | |||
DegradeRule that = (DegradeRule) o; | |||
if (count != that.count) { | |||
return false; | |||
@@ -148,6 +156,13 @@ public class DegradeRule extends AbstractRule { | |||
if (grade != that.grade) { | |||
return false; | |||
} | |||
if (rtSlowRequestAmount != that.rtSlowRequestAmount) { | |||
return false; | |||
} | |||
if (minRequestAmount != that.minRequestAmount) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
@@ -157,6 +172,8 @@ public class DegradeRule extends AbstractRule { | |||
result = 31 * result + new Double(count).hashCode(); | |||
result = 31 * result + timeWindow; | |||
result = 31 * result + grade; | |||
result = 31 * result + rtSlowRequestAmount; | |||
result = 31 * result + minRequestAmount; | |||
return result; | |||
} | |||
@@ -179,20 +196,21 @@ public class DegradeRule extends AbstractRule { | |||
} | |||
// Sentinel will degrade the service only if count exceeds. | |||
if (passCount.incrementAndGet() < RT_MAX_EXCEED_N) { | |||
if (passCount.incrementAndGet() < rtSlowRequestAmount) { | |||
return true; | |||
} | |||
} else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) { | |||
double exception = clusterNode.exceptionQps(); | |||
double success = clusterNode.successQps(); | |||
double total = clusterNode.totalQps(); | |||
// if total qps less than RT_MAX_EXCEED_N, pass. | |||
if (total < RT_MAX_EXCEED_N) { | |||
// if total qps less than minRequestAmount, pass. | |||
if (total < minRequestAmount) { | |||
return true; | |||
} | |||
//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 < RT_MAX_EXCEED_N) { | |||
if (realSuccess <= 0 && exception < minRequestAmount) { | |||
return true; | |||
} | |||
@@ -214,17 +232,37 @@ public class DegradeRule extends AbstractRule { | |||
return false; | |||
} | |||
@Override | |||
public String toString() { | |||
return "DegradeRule{" + | |||
"resource=" + getResource() + | |||
", grade=" + grade + | |||
", count=" + count + | |||
", limitApp=" + getLimitApp() + | |||
", timeWindow=" + timeWindow + | |||
"}"; | |||
"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; | |||
@@ -15,14 +15,6 @@ | |||
*/ | |||
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.context.Context; | |||
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.slots.block.RuleConstant; | |||
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 | |||
@@ -47,12 +47,16 @@ public class DegradeTest { | |||
when(node.getClusterNode()).thenReturn(cn); | |||
when(cn.avgRt()).thenReturn(2d); | |||
int rtSlowRequestAmount = 10; | |||
DegradeRule rule = new DegradeRule(); | |||
rule.setCount(1); | |||
rule.setResource(key); | |||
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)); | |||
} | |||
@@ -69,9 +73,6 @@ public class DegradeTest { | |||
public void testExceptionRatioModeDegrade() throws Throwable { | |||
String key = "test_degrade_exception_ratio"; | |||
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); | |||
Context context = mock(Context.class); | |||
@@ -83,17 +84,39 @@ public class DegradeTest { | |||
rule.setResource(key); | |||
rule.setTimeWindow(2); | |||
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); | |||
rule.setMinRequestAmount(20); | |||
when(cn.successQps()).thenReturn(8d); | |||
// Will fail. | |||
// 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.exceptionQps()).thenReturn(6d); | |||
assertFalse(rule.passCheck(context, node, 1)); | |||
// Restore from the degrade timeout. | |||
TimeUnit.MILLISECONDS.sleep(2200); | |||
when(cn.successQps()).thenReturn(20d); | |||
// Will pass. | |||
when(cn.totalQps()).thenReturn(106d); | |||
when(cn.successQps()).thenReturn(100d); | |||
assertTrue(rule.passCheck(context, node, 1)); | |||
} | |||
@@ -127,4 +150,33 @@ public class DegradeTest { | |||
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)); | |||
} | |||
} |
@@ -15,11 +15,6 @@ | |||
*/ | |||
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; | |||
@@ -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.util.TimeUtil; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.atomic.AtomicInteger; | |||
/** | |||
* <p> | |||
* 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.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); | |||
rule.setTimeWindow(10); | |||
rule.setMinRequestAmount(20); | |||
rules.add(rule); | |||
DegradeRuleManager.loadRules(rules); | |||
} | |||