- Update test cases (use assertEquals(e, a, delta) instead) - Also add `totalPass` method in Node interface Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -45,7 +45,7 @@ public class FluxSentinelOperatorTestIntegrationTest { | |||||
ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName); | ClusterNode cn = ClusterBuilderSlot.getClusterNode(resourceName); | ||||
assertNotNull(cn); | assertNotNull(cn); | ||||
assertEquals(1, cn.passQps()); | |||||
assertEquals(1, cn.passQps(), 0.01); | |||||
assertEquals(1, cn.totalException()); | assertEquals(1, cn.totalException()); | ||||
} | } | ||||
@@ -68,7 +68,7 @@ public class SentinelWebFluxIntegrationTest { | |||||
ClusterNode cn = ClusterBuilderSlot.getClusterNode(url); | ClusterNode cn = ClusterBuilderSlot.getClusterNode(url); | ||||
assertNotNull(cn); | assertNotNull(cn); | ||||
assertEquals(1, cn.passQps()); | |||||
assertEquals(1, cn.passQps(), 0.01); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -94,7 +94,7 @@ public class SentinelWebFluxIntegrationTest { | |||||
.expectBody(String.class).isEqualTo("Hello 2"); | .expectBody(String.class).isEqualTo("Hello 2"); | ||||
ClusterNode cn = ClusterBuilderSlot.getClusterNode(fooPrefix + "*"); | ClusterNode cn = ClusterBuilderSlot.getClusterNode(fooPrefix + "*"); | ||||
assertEquals(2, cn.passQps()); | |||||
assertEquals(2, cn.passQps(), 0.01); | |||||
assertNull(ClusterBuilderSlot.getClusterNode(url1)); | assertNull(ClusterBuilderSlot.getClusterNode(url1)); | ||||
assertNull(ClusterBuilderSlot.getClusterNode(url2)); | assertNull(ClusterBuilderSlot.getClusterNode(url2)); | ||||
@@ -83,7 +83,7 @@ public class CommonFilterTest { | |||||
ClusterNode cn = ClusterBuilderSlot.getClusterNode(url); | ClusterNode cn = ClusterBuilderSlot.getClusterNode(url); | ||||
assertNotNull(cn); | assertNotNull(cn); | ||||
assertEquals(1, cn.passQps()); | |||||
assertEquals(1, cn.passQps(), 0.01); | |||||
testCommonBlockAndRedirectBlockPage(url, cn); | testCommonBlockAndRedirectBlockPage(url, cn); | ||||
@@ -99,7 +99,7 @@ public class CommonFilterTest { | |||||
this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | ||||
.andExpect(status().isOk()) | .andExpect(status().isOk()) | ||||
.andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | .andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | ||||
assertEquals(1, cn.blockQps()); | |||||
assertEquals(1, cn.blockQps(), 0.01); | |||||
// Test for redirect. | // Test for redirect. | ||||
String redirectUrl = "http://some-location.com"; | String redirectUrl = "http://some-location.com"; | ||||
@@ -132,7 +132,7 @@ public class CommonFilterTest { | |||||
.andExpect(status().isOk()) | .andExpect(status().isOk()) | ||||
.andExpect(content().string("Hello 2")); | .andExpect(content().string("Hello 2")); | ||||
ClusterNode cn = ClusterBuilderSlot.getClusterNode(fooPrefix + "*"); | ClusterNode cn = ClusterBuilderSlot.getClusterNode(fooPrefix + "*"); | ||||
assertEquals(2, cn.passQps()); | |||||
assertEquals(2, cn.passQps(), 0.01); | |||||
assertNull(ClusterBuilderSlot.getClusterNode(url1)); | assertNull(ClusterBuilderSlot.getClusterNode(url1)); | ||||
assertNull(ClusterBuilderSlot.getClusterNode(url2)); | assertNull(ClusterBuilderSlot.getClusterNode(url2)); | ||||
@@ -86,7 +86,7 @@ public class CommonFilterMethodTest { | |||||
ClusterNode cnGet = ClusterBuilderSlot.getClusterNode(GET + COLON + url); | ClusterNode cnGet = ClusterBuilderSlot.getClusterNode(GET + COLON + url); | ||||
assertNotNull(cnGet); | assertNotNull(cnGet); | ||||
assertEquals(1, cnGet.passQps()); | |||||
assertEquals(1, cnGet.passQps(), 0.01); | |||||
ClusterNode cnPost = ClusterBuilderSlot.getClusterNode(POST + COLON + url); | ClusterNode cnPost = ClusterBuilderSlot.getClusterNode(POST + COLON + url); | ||||
@@ -98,10 +98,9 @@ public class CommonFilterMethodTest { | |||||
cnPost = ClusterBuilderSlot.getClusterNode(POST + COLON + url); | cnPost = ClusterBuilderSlot.getClusterNode(POST + COLON + url); | ||||
assertNotNull(cnPost); | assertNotNull(cnPost); | ||||
assertEquals(1, cnPost.passQps()); | |||||
assertEquals(1, cnPost.passQps(), 0.01); | |||||
testCommonBlockAndRedirectBlockPage(url, cnGet, cnPost); | testCommonBlockAndRedirectBlockPage(url, cnGet, cnPost); | ||||
} | } | ||||
private void testCommonBlockAndRedirectBlockPage(String url, ClusterNode cnGet, ClusterNode cnPost) throws Exception { | private void testCommonBlockAndRedirectBlockPage(String url, ClusterNode cnGet, ClusterNode cnPost) throws Exception { | ||||
@@ -110,21 +109,20 @@ public class CommonFilterMethodTest { | |||||
this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | ||||
.andExpect(status().isOk()) | .andExpect(status().isOk()) | ||||
.andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | .andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | ||||
assertEquals(1, cnGet.blockQps()); | |||||
assertEquals(1, cnGet.blockQps(), 0.01); | |||||
// Test for post pass | // Test for post pass | ||||
this.mvc.perform(post(url)) | this.mvc.perform(post(url)) | ||||
.andExpect(status().isOk()) | .andExpect(status().isOk()) | ||||
.andExpect(content().string(HELLO_POST_STR)); | .andExpect(content().string(HELLO_POST_STR)); | ||||
assertEquals(2, cnPost.passQps()); | |||||
assertEquals(2, cnPost.passQps(), 0.01); | |||||
FlowRuleManager.loadRules(null); | FlowRuleManager.loadRules(null); | ||||
WebServletConfig.setBlockPage(""); | WebServletConfig.setBlockPage(""); | ||||
} | } | ||||
@After | @After | ||||
public void cleanUp() { | public void cleanUp() { | ||||
FlowRuleManager.loadRules(null); | FlowRuleManager.loadRules(null); | ||||
@@ -48,7 +48,7 @@ public class DefaultNode extends StatisticNode { | |||||
/** | /** | ||||
* The list of all child nodes. | * The list of all child nodes. | ||||
*/ | */ | ||||
private volatile Set<Node> childList = new HashSet<Node>(); | |||||
private volatile Set<Node> childList = new HashSet<>(); | |||||
/** | /** | ||||
* Associated cluster node. | * Associated cluster node. | ||||
@@ -85,7 +85,7 @@ public class DefaultNode extends StatisticNode { | |||||
if (!childList.contains(node)) { | if (!childList.contains(node)) { | ||||
synchronized (this) { | synchronized (this) { | ||||
if (!childList.contains(node)) { | if (!childList.contains(node)) { | ||||
Set<Node> newSet = new HashSet<Node>(childList.size() + 1); | |||||
Set<Node> newSet = new HashSet<>(childList.size() + 1); | |||||
newSet.addAll(childList); | newSet.addAll(childList); | ||||
newSet.add(node); | newSet.add(node); | ||||
childList = newSet; | childList = newSet; | ||||
@@ -99,7 +99,7 @@ public class DefaultNode extends StatisticNode { | |||||
* Reset the child node list. | * Reset the child node list. | ||||
*/ | */ | ||||
public void removeChildList() { | public void removeChildList() { | ||||
this.childList = new HashSet<Node>(); | |||||
this.childList = new HashSet<>(); | |||||
} | } | ||||
public Set<Node> getChildList() { | public Set<Node> getChildList() { | ||||
@@ -43,9 +43,9 @@ public class EntranceNode extends DefaultNode { | |||||
} | } | ||||
@Override | @Override | ||||
public long avgRt() { | |||||
long total = 0; | |||||
long totalQps = 0; | |||||
public double avgRt() { | |||||
double total = 0; | |||||
double totalQps = 0; | |||||
for (Node node : getChildList()) { | for (Node node : getChildList()) { | ||||
total += node.avgRt() * node.passQps(); | total += node.avgRt() * node.passQps(); | ||||
totalQps += node.passQps(); | totalQps += node.passQps(); | ||||
@@ -54,8 +54,8 @@ public class EntranceNode extends DefaultNode { | |||||
} | } | ||||
@Override | @Override | ||||
public long blockQps() { | |||||
long blockQps = 0; | |||||
public double blockQps() { | |||||
double blockQps = 0; | |||||
for (Node node : getChildList()) { | for (Node node : getChildList()) { | ||||
blockQps += node.blockQps(); | blockQps += node.blockQps(); | ||||
} | } | ||||
@@ -81,8 +81,8 @@ public class EntranceNode extends DefaultNode { | |||||
} | } | ||||
@Override | @Override | ||||
public long totalQps() { | |||||
long r = 0; | |||||
public double totalQps() { | |||||
double r = 0; | |||||
for (Node node : getChildList()) { | for (Node node : getChildList()) { | ||||
r += node.totalQps(); | r += node.totalQps(); | ||||
} | } | ||||
@@ -90,8 +90,8 @@ public class EntranceNode extends DefaultNode { | |||||
} | } | ||||
@Override | @Override | ||||
public long successQps() { | |||||
long r = 0; | |||||
public double successQps() { | |||||
double r = 0; | |||||
for (Node node : getChildList()) { | for (Node node : getChildList()) { | ||||
r += node.successQps(); | r += node.successQps(); | ||||
} | } | ||||
@@ -99,8 +99,8 @@ public class EntranceNode extends DefaultNode { | |||||
} | } | ||||
@Override | @Override | ||||
public long passQps() { | |||||
long r = 0; | |||||
public double passQps() { | |||||
double r = 0; | |||||
for (Node node : getChildList()) { | for (Node node : getChildList()) { | ||||
r += node.passQps(); | r += node.passQps(); | ||||
} | } | ||||
@@ -116,4 +116,12 @@ public class EntranceNode extends DefaultNode { | |||||
return r; | return r; | ||||
} | } | ||||
@Override | |||||
public long totalPass() { | |||||
long r = 0; | |||||
for (Node node : getChildList()) { | |||||
r += node.totalPass(); | |||||
} | |||||
return r; | |||||
} | |||||
} | } |
@@ -19,98 +19,125 @@ import java.util.Map; | |||||
import com.alibaba.csp.sentinel.Entry; | import com.alibaba.csp.sentinel.Entry; | ||||
import com.alibaba.csp.sentinel.node.metric.MetricNode; | import com.alibaba.csp.sentinel.node.metric.MetricNode; | ||||
import com.alibaba.csp.sentinel.slots.statistic.metric.DebugSupport; | |||||
/** | /** | ||||
* This class holds real-time statistics for a resource. | |||||
* Holds real-time statistics for resources. | |||||
* | * | ||||
* @author qinan.qn | * @author qinan.qn | ||||
* @author leyou | * @author leyou | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
public interface Node { | |||||
public interface Node extends DebugSupport { | |||||
/** | /** | ||||
* Get incoming request per minute. {@code pass + block} | |||||
* Get incoming request per minute ({@code pass + block}). | |||||
* | |||||
* @return total request count per minute | |||||
*/ | */ | ||||
long totalRequest(); | long totalRequest(); | ||||
/** | |||||
* Get pass count per minute. | |||||
* | |||||
* @return total passed request count per minute | |||||
* @since 1.5.0 | |||||
*/ | |||||
long totalPass(); | |||||
/** | /** | ||||
* Get {@link Entry#exit()} count per minute. | * Get {@link Entry#exit()} count per minute. | ||||
* | * | ||||
* @return Outgoing request per minute. | |||||
* @return total completed request count per minute | |||||
*/ | */ | ||||
long totalSuccess(); | long totalSuccess(); | ||||
/** | /** | ||||
* Get block request count per minute. | |||||
* Get blocked request count per minute (totalBlockRequest). | |||||
* | |||||
* @return total blocked request count per minute | |||||
*/ | */ | ||||
long blockRequest(); | long blockRequest(); | ||||
/** | /** | ||||
* Get exception count per minute. | * Get exception count per minute. | ||||
* | |||||
* @return total business exception count per minute | |||||
*/ | */ | ||||
long totalException(); | long totalException(); | ||||
/** | /** | ||||
* Get pass request per second. | * Get pass request per second. | ||||
* | |||||
* @return QPS of passed requests | |||||
*/ | */ | ||||
long passQps(); | |||||
double passQps(); | |||||
/** | /** | ||||
* Get block request per second. | * Get block request per second. | ||||
* | |||||
* @return QPS of blocked requests | |||||
*/ | */ | ||||
long blockQps(); | |||||
double blockQps(); | |||||
/** | /** | ||||
* Get {@link #passQps()} + {@link #blockQps()} request per second. | * Get {@link #passQps()} + {@link #blockQps()} request per second. | ||||
* | |||||
* @return QPS of passed and blocked requests | |||||
*/ | */ | ||||
long totalQps(); | |||||
double totalQps(); | |||||
/** | /** | ||||
* Get {@link Entry#exit()} request per second. | * Get {@link Entry#exit()} request per second. | ||||
* | |||||
* @return QPS of completed requests | |||||
*/ | */ | ||||
long successQps(); | |||||
double successQps(); | |||||
/** | /** | ||||
* Get estimated max success QPS till now. | * Get estimated max success QPS till now. | ||||
* | * | ||||
* @return max success QPS | |||||
* @return max completed QPS | |||||
*/ | */ | ||||
long maxSuccessQps(); | |||||
double maxSuccessQps(); | |||||
/** | /** | ||||
* Get exception count per second. | * Get exception count per second. | ||||
* | |||||
* @return QPS of exception occurs | |||||
*/ | */ | ||||
long exceptionQps(); | |||||
double exceptionQps(); | |||||
/** | /** | ||||
* Get average rt per second. | * Get average rt per second. | ||||
* | * | ||||
* @return average response time per second | * @return average response time per second | ||||
*/ | */ | ||||
long avgRt(); | |||||
double avgRt(); | |||||
/** | /** | ||||
* Get minimal response time. | * Get minimal response time. | ||||
* | * | ||||
* @return recorded minimal response time | * @return recorded minimal response time | ||||
*/ | */ | ||||
long minRt(); | |||||
double minRt(); | |||||
/** | /** | ||||
* Get current active thread count. | * Get current active thread count. | ||||
* | |||||
* @return current active thread count | |||||
*/ | */ | ||||
int curThreadNum(); | int curThreadNum(); | ||||
/** | /** | ||||
* Get last second block QPS. | * Get last second block QPS. | ||||
*/ | */ | ||||
long previousBlockQps(); | |||||
double previousBlockQps(); | |||||
/** | /** | ||||
* Last window QPS. | * Last window QPS. | ||||
*/ | */ | ||||
long previousPassQps(); | |||||
double previousPassQps(); | |||||
/** | /** | ||||
* Fetch all valid metric nodes of resources. | * Fetch all valid metric nodes of resources. | ||||
@@ -129,18 +156,22 @@ public interface Node { | |||||
/** | /** | ||||
* Add rt and success count. | * Add rt and success count. | ||||
* | * | ||||
* @param rt response time | |||||
* @param rt response time | |||||
* @param success success count to add | * @param success success count to add | ||||
*/ | */ | ||||
void addRtAndSuccess(long rt, int success); | void addRtAndSuccess(long rt, int success); | ||||
/** | /** | ||||
* Increase the block count. | * Increase the block count. | ||||
* | |||||
* @param count count to add | |||||
*/ | */ | ||||
void increaseBlockQps(int count); | void increaseBlockQps(int count); | ||||
/** | /** | ||||
* Increase the biz exception count. | |||||
* Add the biz exception count. | |||||
* | |||||
* @param count count to add | |||||
*/ | */ | ||||
void increaseExceptionQps(int count); | void increaseExceptionQps(int count); | ||||
@@ -159,9 +190,4 @@ public interface Node { | |||||
* {@link SampleCountProperty#SAMPLE_COUNT} is changed. | * {@link SampleCountProperty#SAMPLE_COUNT} is changed. | ||||
*/ | */ | ||||
void reset(); | void reset(); | ||||
/** | |||||
* Debug only. | |||||
*/ | |||||
void debug(); | |||||
} | } |
@@ -151,28 +151,33 @@ public class StatisticNode implements Node { | |||||
return totalRequest; | return totalRequest; | ||||
} | } | ||||
@Override | |||||
public long totalPass() { | |||||
return rollingCounterInMinute.pass(); | |||||
} | |||||
@Override | @Override | ||||
public long blockRequest() { | public long blockRequest() { | ||||
return rollingCounterInMinute.block(); | return rollingCounterInMinute.block(); | ||||
} | } | ||||
@Override | @Override | ||||
public long blockQps() { | |||||
return rollingCounterInSecond.block() / (long) rollingCounterInSecond.getWindowIntervalInSec(); | |||||
public double blockQps() { | |||||
return rollingCounterInSecond.block() / rollingCounterInSecond.getWindowIntervalInSec(); | |||||
} | } | ||||
@Override | @Override | ||||
public long previousBlockQps() { | |||||
public double previousBlockQps() { | |||||
return this.rollingCounterInMinute.previousWindowBlock(); | return this.rollingCounterInMinute.previousWindowBlock(); | ||||
} | } | ||||
@Override | @Override | ||||
public long previousPassQps() { | |||||
public double previousPassQps() { | |||||
return this.rollingCounterInMinute.previousWindowPass(); | return this.rollingCounterInMinute.previousWindowPass(); | ||||
} | } | ||||
@Override | @Override | ||||
public long totalQps() { | |||||
public double totalQps() { | |||||
return passQps() + blockQps(); | return passQps() + blockQps(); | ||||
} | } | ||||
@@ -182,8 +187,8 @@ public class StatisticNode implements Node { | |||||
} | } | ||||
@Override | @Override | ||||
public long exceptionQps() { | |||||
return rollingCounterInSecond.exception() / (long) rollingCounterInSecond.getWindowIntervalInSec(); | |||||
public double exceptionQps() { | |||||
return rollingCounterInSecond.exception() / rollingCounterInSecond.getWindowIntervalInSec(); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -192,32 +197,32 @@ public class StatisticNode implements Node { | |||||
} | } | ||||
@Override | @Override | ||||
public long passQps() { | |||||
return rollingCounterInSecond.pass() / (long) rollingCounterInSecond.getWindowIntervalInSec(); | |||||
public double passQps() { | |||||
return rollingCounterInSecond.pass() / rollingCounterInSecond.getWindowIntervalInSec(); | |||||
} | } | ||||
@Override | @Override | ||||
public long successQps() { | |||||
return rollingCounterInSecond.success() / (long) rollingCounterInSecond.getWindowIntervalInSec(); | |||||
public double successQps() { | |||||
return rollingCounterInSecond.success() / rollingCounterInSecond.getWindowIntervalInSec(); | |||||
} | } | ||||
@Override | @Override | ||||
public long maxSuccessQps() { | |||||
public double maxSuccessQps() { | |||||
return rollingCounterInSecond.maxSuccess() * rollingCounterInSecond.getSampleCount(); | return rollingCounterInSecond.maxSuccess() * rollingCounterInSecond.getSampleCount(); | ||||
} | } | ||||
@Override | @Override | ||||
public long avgRt() { | |||||
public double avgRt() { | |||||
long successCount = rollingCounterInSecond.success(); | long successCount = rollingCounterInSecond.success(); | ||||
if (successCount == 0) { | if (successCount == 0) { | ||||
return 0; | return 0; | ||||
} | } | ||||
return rollingCounterInSecond.rt() / successCount; | |||||
return rollingCounterInSecond.rt() * 1.0 / successCount; | |||||
} | } | ||||
@Override | @Override | ||||
public long minRt() { | |||||
public double minRt() { | |||||
return rollingCounterInSecond.minRt(); | return rollingCounterInSecond.minRt(); | ||||
} | } | ||||
@@ -184,7 +184,7 @@ public class DegradeRule extends AbstractRule { | |||||
} 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(); | ||||
long total = clusterNode.totalQps(); | |||||
double total = clusterNode.totalQps(); | |||||
// if total qps less than RT_MAX_EXCEED_N, pass. | // if total qps less than RT_MAX_EXCEED_N, pass. | ||||
if (total < RT_MAX_EXCEED_N) { | if (total < RT_MAX_EXCEED_N) { | ||||
return true; | return true; | ||||
@@ -112,9 +112,9 @@ public class WarmUpController implements TrafficShapingController { | |||||
@Override | @Override | ||||
public boolean canPass(Node node, int acquireCount, boolean prioritized) { | public boolean canPass(Node node, int acquireCount, boolean prioritized) { | ||||
long passQps = node.passQps(); | |||||
long passQps = (long) node.passQps(); | |||||
long previousQps = node.previousPassQps(); | |||||
long previousQps = (long) node.previousPassQps(); | |||||
syncToken(previousQps); | syncToken(previousQps); | ||||
// 开始计算它的斜率 | // 开始计算它的斜率 | ||||
@@ -22,19 +22,16 @@ import com.alibaba.csp.sentinel.util.TimeUtil; | |||||
/** | /** | ||||
* @author jialiang.linjl | * @author jialiang.linjl | ||||
* @since 1.4.0 | |||||
*/ | */ | ||||
public class WarmUpRateLimiterController extends WarmUpController { | public class WarmUpRateLimiterController extends WarmUpController { | ||||
final int timeOutInMs; | |||||
final AtomicLong latestPassedTime = new AtomicLong(-1); | |||||
private final int timeoutInMs; | |||||
private final AtomicLong latestPassedTime = new AtomicLong(-1); | |||||
/** | |||||
* @param count | |||||
* @param warmUpPeriodSec | |||||
*/ | |||||
public WarmUpRateLimiterController(double count, int warmUpPeriodSec, int timeOutMs, int coldFactor) { | public WarmUpRateLimiterController(double count, int warmUpPeriodSec, int timeOutMs, int coldFactor) { | ||||
super(count, warmUpPeriodSec, coldFactor); | super(count, warmUpPeriodSec, coldFactor); | ||||
this.timeOutInMs = timeOutMs; | |||||
this.timeoutInMs = timeOutMs; | |||||
} | } | ||||
@Override | @Override | ||||
@@ -44,7 +41,7 @@ public class WarmUpRateLimiterController extends WarmUpController { | |||||
@Override | @Override | ||||
public boolean canPass(Node node, int acquireCount, boolean prioritized) { | public boolean canPass(Node node, int acquireCount, boolean prioritized) { | ||||
long previousQps = node.previousPassQps(); | |||||
long previousQps = (long) node.previousPassQps(); | |||||
syncToken(previousQps); | syncToken(previousQps); | ||||
long currentTime = TimeUtil.currentTimeMillis(); | long currentTime = TimeUtil.currentTimeMillis(); | ||||
@@ -68,13 +65,13 @@ public class WarmUpRateLimiterController extends WarmUpController { | |||||
return true; | return true; | ||||
} else { | } else { | ||||
long waitTime = costTime + latestPassedTime.get() - currentTime; | long waitTime = costTime + latestPassedTime.get() - currentTime; | ||||
if (waitTime > timeOutInMs) { | |||||
if (waitTime > timeoutInMs) { | |||||
return false; | return false; | ||||
} else { | } else { | ||||
long oldTime = latestPassedTime.addAndGet(costTime); | long oldTime = latestPassedTime.addAndGet(costTime); | ||||
try { | try { | ||||
waitTime = oldTime - TimeUtil.currentTimeMillis(); | waitTime = oldTime - TimeUtil.currentTimeMillis(); | ||||
if (waitTime > timeOutInMs) { | |||||
if (waitTime > timeoutInMs) { | |||||
latestPassedTime.addAndGet(-costTime); | latestPassedTime.addAndGet(-costTime); | ||||
return false; | return false; | ||||
} | } | ||||
@@ -89,4 +86,3 @@ public class WarmUpRateLimiterController extends WarmUpController { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,28 @@ | |||||
/* | |||||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
package com.alibaba.csp.sentinel.slots.statistic.metric; | |||||
/** | |||||
* @author Eric Zhao | |||||
* @since 1.5.0 | |||||
*/ | |||||
public interface DebugSupport { | |||||
/** | |||||
* For debug; | |||||
*/ | |||||
void debug(); | |||||
} |
@@ -139,18 +139,18 @@ public class ClusterNodeTest { | |||||
// test count<=0, no exceptionQps added | // test count<=0, no exceptionQps added | ||||
clusterNode.trace(exception, 0); | clusterNode.trace(exception, 0); | ||||
clusterNode.trace(exception, -1); | clusterNode.trace(exception, -1); | ||||
assertEquals(0, clusterNode.exceptionQps()); | |||||
assertEquals(0, clusterNode.exceptionQps(), 0.01); | |||||
assertEquals(0, clusterNode.totalException()); | assertEquals(0, clusterNode.totalException()); | ||||
// test count=1, not BlockException, 1 exceptionQps added | // test count=1, not BlockException, 1 exceptionQps added | ||||
clusterNode.trace(exception, 1); | clusterNode.trace(exception, 1); | ||||
assertEquals(1, clusterNode.exceptionQps()); | |||||
assertEquals(1, clusterNode.exceptionQps(), 0.01); | |||||
assertEquals(1, clusterNode.totalException()); | assertEquals(1, clusterNode.totalException()); | ||||
// test count=1, BlockException, no exceptionQps added | // test count=1, BlockException, no exceptionQps added | ||||
FlowException flowException = new FlowException("flow"); | FlowException flowException = new FlowException("flow"); | ||||
clusterNode.trace(flowException, 1); | clusterNode.trace(flowException, 1); | ||||
assertEquals(1, clusterNode.exceptionQps()); | |||||
assertEquals(1, clusterNode.exceptionQps(), 0.01); | |||||
assertEquals(1, clusterNode.totalException()); | assertEquals(1, clusterNode.totalException()); | ||||
} | } | ||||
} | } |
@@ -92,9 +92,9 @@ public class StatisticNodeTest { | |||||
tickEs.shutdown(); | tickEs.shutdown(); | ||||
// now no biz method execute, so there is no curThreadNum,passQps,successQps | // now no biz method execute, so there is no curThreadNum,passQps,successQps | ||||
assertEquals(0, node.curThreadNum()); | |||||
assertEquals(0, node.passQps()); | |||||
assertEquals(0, node.successQps()); | |||||
assertEquals(0, node.curThreadNum(), 0.01); | |||||
assertEquals(0, node.passQps(), 0.01); | |||||
assertEquals(0, node.successQps(), 0.01); | |||||
// note: total time cost should be controlled within 1 minute, | // note: total time cost should be controlled within 1 minute, | ||||
// as the node.totalRequest() holding statistics of recent 60 seconds | // as the node.totalRequest() holding statistics of recent 60 seconds | ||||
@@ -105,7 +105,7 @@ public class StatisticNodeTest { | |||||
assertEquals(totalRequest, node.totalSuccess()); | assertEquals(totalRequest, node.totalSuccess()); | ||||
// now there are no data in time span, so the minRT should be equals to TIME_DROP_VALVE | // now there are no data in time span, so the minRT should be equals to TIME_DROP_VALVE | ||||
assertEquals(node.minRt(), Constants.TIME_DROP_VALVE); | |||||
assertEquals(node.minRt(), Constants.TIME_DROP_VALVE, 0.01); | |||||
log("===================================================="); | log("===================================================="); | ||||
log("testStatisticThreadNumAndQps done, cost " + (TimeUtil.currentTimeMillis() - testStartTime) + "ms"); | log("testStatisticThreadNumAndQps done, cost " + (TimeUtil.currentTimeMillis() - testStartTime) + "ms"); | ||||
@@ -45,7 +45,7 @@ public class DegradeTest { | |||||
Context context = mock(Context.class); | Context context = mock(Context.class); | ||||
DefaultNode node = mock(DefaultNode.class); | DefaultNode node = mock(DefaultNode.class); | ||||
when(node.getClusterNode()).thenReturn(cn); | when(node.getClusterNode()).thenReturn(cn); | ||||
when(cn.avgRt()).thenReturn(2L); | |||||
when(cn.avgRt()).thenReturn(2d); | |||||
DegradeRule rule = new DegradeRule(); | DegradeRule rule = new DegradeRule(); | ||||
rule.setCount(1); | rule.setCount(1); | ||||
@@ -69,9 +69,9 @@ 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(2L); | |||||
when(cn.exceptionQps()).thenReturn(2d); | |||||
// Indicates that there are QPS more than min threshold. | // Indicates that there are QPS more than min threshold. | ||||
when(cn.totalQps()).thenReturn(12L); | |||||
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); | ||||
@@ -84,7 +84,7 @@ public class DegradeTest { | |||||
rule.setTimeWindow(2); | rule.setTimeWindow(2); | ||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); | rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); | ||||
when(cn.successQps()).thenReturn(8L); | |||||
when(cn.successQps()).thenReturn(8d); | |||||
// Will fail. | // Will fail. | ||||
assertFalse(rule.passCheck(context, node, 1)); | assertFalse(rule.passCheck(context, node, 1)); | ||||
@@ -92,7 +92,7 @@ public class DegradeTest { | |||||
// Restore from the degrade timeout. | // Restore from the degrade timeout. | ||||
TimeUnit.MILLISECONDS.sleep(2200); | TimeUnit.MILLISECONDS.sleep(2200); | ||||
when(cn.successQps()).thenReturn(20L); | |||||
when(cn.successQps()).thenReturn(20d); | |||||
// Will pass. | // Will pass. | ||||
assertTrue(rule.passCheck(context, node, 1)); | assertTrue(rule.passCheck(context, node, 1)); | ||||
} | } | ||||
@@ -18,9 +18,12 @@ package com.alibaba.csp.sentinel.slots.block.flow; | |||||
import static org.junit.Assert.assertTrue; | import static org.junit.Assert.assertTrue; | ||||
import static org.junit.Assert.fail; | import static org.junit.Assert.fail; | ||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import org.junit.After; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.alibaba.csp.sentinel.Entry; | import com.alibaba.csp.sentinel.Entry; | ||||
@@ -34,6 +37,16 @@ import com.alibaba.csp.sentinel.slots.block.RuleConstant; | |||||
*/ | */ | ||||
public class FlowPartialIntegrationTest { | public class FlowPartialIntegrationTest { | ||||
@Before | |||||
public void setUp() throws Exception { | |||||
FlowRuleManager.loadRules(new ArrayList<FlowRule>()); | |||||
} | |||||
@After | |||||
public void tearDown() throws Exception { | |||||
FlowRuleManager.loadRules(new ArrayList<FlowRule>()); | |||||
} | |||||
@Test | @Test | ||||
public void testQPSGrade() { | public void testQPSGrade() { | ||||
FlowRule flowRule = new FlowRule(); | FlowRule flowRule = new FlowRule(); | ||||
@@ -15,7 +15,7 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.slots.block.flow; | package com.alibaba.csp.sentinel.slots.block.flow; | ||||
import static org.junit.Assert.assertTrue; | |||||
import static org.junit.Assert.*; | |||||
import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||
import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||
@@ -52,15 +52,15 @@ public class FlowRuleTest { | |||||
when(context.getOrigin()).thenReturn(""); | when(context.getOrigin()).thenReturn(""); | ||||
when(node.getClusterNode()).thenReturn(cn); | when(node.getClusterNode()).thenReturn(cn); | ||||
when(cn.passQps()).thenReturn(1l); | |||||
when(cn.passQps()).thenReturn(1d); | |||||
assertTrue(flowRule.passCheck(context, node, 1, new Object[0]) == false); | |||||
assertFalse(flowRule.passCheck(context, node, 1)); | |||||
flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD); | flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD); | ||||
defaultController = new DefaultController(1, flowRule.getGrade()); | defaultController = new DefaultController(1, flowRule.getGrade()); | ||||
flowRule.setRater(defaultController); | flowRule.setRater(defaultController); | ||||
when(cn.curThreadNum()).thenReturn(1); | when(cn.curThreadNum()).thenReturn(1); | ||||
assertTrue(flowRule.passCheck(context, node, 1, new Object[0]) == false); | |||||
assertTrue(!flowRule.passCheck(context, node, 1)); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -79,17 +79,16 @@ public class FlowRuleTest { | |||||
DefaultNode dn = mock(DefaultNode.class); | DefaultNode dn = mock(DefaultNode.class); | ||||
when(context.getName()).thenReturn("entry1"); | when(context.getName()).thenReturn("entry1"); | ||||
when(dn.passQps()).thenReturn(1l); | |||||
assertTrue(flowRule.passCheck(context, dn, 1, new Object[0]) == false); | |||||
when(dn.passQps()).thenReturn(1d); | |||||
assertFalse(flowRule.passCheck(context, dn, 1)); | |||||
when(context.getName()).thenReturn("entry2"); | when(context.getName()).thenReturn("entry2"); | ||||
assertTrue(flowRule.passCheck(context, dn, 1, new Object[0])); | |||||
assertTrue(flowRule.passCheck(context, dn, 1)); | |||||
// Strategy == relate | // Strategy == relate | ||||
flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN); | flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN); | ||||
ClusterNode cn = mock(ClusterNode.class); | ClusterNode cn = mock(ClusterNode.class); | ||||
assertTrue(flowRule.passCheck(context, dn, 1, new Object[0]) == true); | |||||
assertTrue(flowRule.passCheck(context, dn, 1)); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -106,7 +105,7 @@ public class FlowRuleTest { | |||||
Context context = mock(Context.class); | Context context = mock(Context.class); | ||||
DefaultNode dn = mock(DefaultNode.class); | DefaultNode dn = mock(DefaultNode.class); | ||||
when(context.getOrigin()).thenReturn("origin1"); | when(context.getOrigin()).thenReturn("origin1"); | ||||
when(dn.passQps()).thenReturn(1l); | |||||
when(dn.passQps()).thenReturn(1d); | |||||
when(context.getOriginNode()).thenReturn(dn); | when(context.getOriginNode()).thenReturn(dn); | ||||
/* | /* | ||||
@@ -115,9 +114,9 @@ public class FlowRuleTest { | |||||
*/ | */ | ||||
ClusterNode cn = mock(ClusterNode.class); | ClusterNode cn = mock(ClusterNode.class); | ||||
when(dn.getClusterNode()).thenReturn(cn); | when(dn.getClusterNode()).thenReturn(cn); | ||||
when(cn.passQps()).thenReturn(1l); | |||||
when(cn.passQps()).thenReturn(1d); | |||||
assertTrue(flowRule.passCheck(context, dn, 1, new Object[0]) == false); | assertTrue(flowRule.passCheck(context, dn, 1, new Object[0]) == false); | ||||
when(cn.passQps()).thenReturn(0l); | |||||
when(cn.passQps()).thenReturn(0d); | |||||
assertTrue(flowRule.passCheck(context, dn, 1, new Object[0])); | assertTrue(flowRule.passCheck(context, dn, 1, new Object[0])); | ||||
flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN); | flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN); | ||||
@@ -16,7 +16,7 @@ public class DefaultControllerTest { | |||||
@Test | @Test | ||||
public void testCanPassForQps() { | public void testCanPassForQps() { | ||||
long threshold = 10; | |||||
double threshold = 10; | |||||
TrafficShapingController controller = new DefaultController(threshold, RuleConstant.FLOW_GRADE_QPS); | TrafficShapingController controller = new DefaultController(threshold, RuleConstant.FLOW_GRADE_QPS); | ||||
Node node = mock(Node.class); | Node node = mock(Node.class); | ||||
when(node.passQps()).thenReturn(threshold - 1) | when(node.passQps()).thenReturn(threshold - 1) | ||||
@@ -38,26 +38,26 @@ public class WarmUpControllerTest extends AbstractTimeBasedTest { | |||||
Node node = mock(Node.class); | Node node = mock(Node.class); | ||||
when(node.passQps()).thenReturn(8L); | |||||
when(node.previousPassQps()).thenReturn(1L); | |||||
when(node.passQps()).thenReturn(8d); | |||||
when(node.previousPassQps()).thenReturn(1d); | |||||
assertFalse(warmupController.canPass(node, 1)); | assertFalse(warmupController.canPass(node, 1)); | ||||
when(node.passQps()).thenReturn(1L); | |||||
when(node.previousPassQps()).thenReturn(1L); | |||||
when(node.passQps()).thenReturn(1d); | |||||
when(node.previousPassQps()).thenReturn(1d); | |||||
assertTrue(warmupController.canPass(node, 1)); | assertTrue(warmupController.canPass(node, 1)); | ||||
when(node.previousPassQps()).thenReturn(10L); | |||||
when(node.previousPassQps()).thenReturn(10d); | |||||
for (int i = 0; i < 100; i++) { | for (int i = 0; i < 100; i++) { | ||||
sleep(100); | sleep(100); | ||||
warmupController.canPass(node, 1); | warmupController.canPass(node, 1); | ||||
} | } | ||||
when(node.passQps()).thenReturn(8L); | |||||
when(node.passQps()).thenReturn(8d); | |||||
assertTrue(warmupController.canPass(node, 1)); | assertTrue(warmupController.canPass(node, 1)); | ||||
when(node.passQps()).thenReturn(10L); | |||||
when(node.passQps()).thenReturn(10d); | |||||
assertFalse(warmupController.canPass(node, 1)); | assertFalse(warmupController.canPass(node, 1)); | ||||
} | } | ||||
} | } |
@@ -22,15 +22,15 @@ public class WarmUpRateLimiterControllerTest { | |||||
Node node = mock(Node.class); | Node node = mock(Node.class); | ||||
when(node.passQps()).thenReturn(100L); | |||||
when(node.previousPassQps()).thenReturn(100L); | |||||
when(node.passQps()).thenReturn(100d); | |||||
when(node.previousPassQps()).thenReturn(100d); | |||||
assertTrue(controller.canPass(node, 1)); | assertTrue(controller.canPass(node, 1)); | ||||
long start = System.currentTimeMillis(); | long start = System.currentTimeMillis(); | ||||
assertTrue(controller.canPass(node, 1)); | assertTrue(controller.canPass(node, 1)); | ||||
long cost = System.currentTimeMillis() - start; | long cost = System.currentTimeMillis() - start; | ||||
assertTrue(cost >= 100 && cost <= 110); | |||||
assertTrue(cost >= 100 && cost <= 120); | |||||
} | } | ||||
@Test | @Test | ||||
@@ -39,8 +39,8 @@ public class WarmUpRateLimiterControllerTest { | |||||
Node node = mock(Node.class); | Node node = mock(Node.class); | ||||
when(node.passQps()).thenReturn(100L); | |||||
when(node.previousPassQps()).thenReturn(100L); | |||||
when(node.passQps()).thenReturn(100d); | |||||
when(node.previousPassQps()).thenReturn(100d); | |||||
assertTrue(controller.canPass(node, 1)); | assertTrue(controller.canPass(node, 1)); | ||||
@@ -63,12 +63,12 @@ public class NodeVo { | |||||
vo.parentId = parentId; | vo.parentId = parentId; | ||||
vo.resource = node.getId().getShowName(); | vo.resource = node.getId().getShowName(); | ||||
vo.threadNum = node.curThreadNum(); | vo.threadNum = node.curThreadNum(); | ||||
vo.passQps = node.passQps(); | |||||
vo.blockQps = node.blockQps(); | |||||
vo.totalQps = node.totalQps(); | |||||
vo.averageRt = node.avgRt(); | |||||
vo.successQps = node.successQps(); | |||||
vo.exceptionQps = node.exceptionQps(); | |||||
vo.passQps = (long) node.passQps(); | |||||
vo.blockQps = (long) node.blockQps(); | |||||
vo.totalQps = (long) node.totalQps(); | |||||
vo.averageRt = (long) node.avgRt(); | |||||
vo.successQps = (long) node.successQps(); | |||||
vo.exceptionQps = (long) node.exceptionQps(); | |||||
vo.oneMinuteException = node.totalException(); | vo.oneMinuteException = node.totalException(); | ||||
vo.oneMinutePass = node.totalRequest() - node.blockRequest(); | vo.oneMinutePass = node.totalRequest() - node.blockRequest(); | ||||
vo.oneMinuteBlock = node.blockRequest(); | vo.oneMinuteBlock = node.blockRequest(); | ||||
@@ -102,12 +102,12 @@ public class NodeVo { | |||||
NodeVo vo = new NodeVo(); | NodeVo vo = new NodeVo(); | ||||
vo.resource = name; | vo.resource = name; | ||||
vo.threadNum = node.curThreadNum(); | vo.threadNum = node.curThreadNum(); | ||||
vo.passQps = node.passQps(); | |||||
vo.blockQps = node.blockQps(); | |||||
vo.totalQps = node.totalQps(); | |||||
vo.averageRt = node.avgRt(); | |||||
vo.successQps = node.successQps(); | |||||
vo.exceptionQps = node.exceptionQps(); | |||||
vo.passQps = (long) node.passQps(); | |||||
vo.blockQps = (long) node.blockQps(); | |||||
vo.totalQps = (long) node.totalQps(); | |||||
vo.averageRt = (long) node.avgRt(); | |||||
vo.successQps = (long) node.successQps(); | |||||
vo.exceptionQps = (long) node.exceptionQps(); | |||||
vo.oneMinuteException = node.totalException(); | vo.oneMinuteException = node.totalException(); | ||||
vo.oneMinutePass = node.totalRequest() - node.blockRequest(); | vo.oneMinutePass = node.totalRequest() - node.blockRequest(); | ||||
vo.oneMinuteBlock = node.blockRequest(); | vo.oneMinuteBlock = node.blockRequest(); | ||||