Browse Source

Refactor the constructor and units of LeapArray and related statistic class

- The constructor now accept `sampleCount` and `windowIntervalMs` so that it can match the two basic properties

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
master
Eric Zhao 6 years ago
parent
commit
a2b91a9030
14 changed files with 99 additions and 72 deletions
  1. +8
    -6
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/IntervalProperty.java
  2. +8
    -8
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/StatisticNode.java
  3. +3
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/RuleConstant.java
  4. +20
    -14
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArray.java
  5. +12
    -6
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java
  6. +4
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/Metric.java
  7. +2
    -6
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/MetricsLeapArray.java
  8. +0
    -1
      sentinel-core/src/test/java/com/alibaba/csp/sentinel/base/metric/ArrayMetricTest.java
  9. +15
    -11
      sentinel-core/src/test/java/com/alibaba/csp/sentinel/base/metric/MetricsLeapArrayTest.java
  10. +3
    -3
      sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArrayTest.java
  11. +0
    -1
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleManager.java
  12. +17
    -2
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParameterMetric.java
  13. +4
    -11
      sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/HotParameterLeapArray.java
  14. +3
    -3
      sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/statistic/metric/HotParameterLeapArrayTest.java

+ 8
- 6
sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/IntervalProperty.java View File

@@ -18,25 +18,27 @@ package com.alibaba.csp.sentinel.node;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.property.SentinelProperty;
import com.alibaba.csp.sentinel.property.SimplePropertyListener;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot;

/***
/**
* QPS statistics interval.
*
* @author youji.zj
* @author jialiang.linjl
* @author CarpenterLee
* @author Carpenter Lee
* @author Eric Zhao
*/
public class IntervalProperty {

/**
* <p>Interval in milliseconds. This variable determines sensitivity of the QPS calculation.</p>
* <p>
* Interval in seconds. This variable determines sensitivity of the QPS calculation.
* </p>
* DO NOT MODIFY this value directly, use {@link #updateInterval(int)}, otherwise the modification will not
* take effect.
* </p>
*/
public static volatile int INTERVAL = 1;
public static volatile int INTERVAL = RuleConstant.DEFAULT_WINDOW_INTERVAL_MS;

public static void register2Property(SentinelProperty<Integer> property) {
property.addListener(new SimplePropertyListener<Integer>() {
@@ -60,7 +62,7 @@ public class IntervalProperty {
INTERVAL = newInterval;
ClusterBuilderSlot.resetClusterNodes();
}
RecordLog.info("INTERVAL updated to: " + INTERVAL);
RecordLog.info("[IntervalProperty] INTERVAL updated to: " + INTERVAL);
}

}

+ 8
- 8
sentinel-core/src/main/java/com/alibaba/csp/sentinel/node/StatisticNode.java View File

@@ -92,14 +92,14 @@ public class StatisticNode implements Node {
* Holds statistics of the recent {@code INTERVAL} seconds. The {@code INTERVAL} is divided into time spans
* by given {@code sampleCount}.
*/
private transient volatile Metric rollingCounterInSecond = new ArrayMetric(1000 / SampleCountProperty.SAMPLE_COUNT,
private transient volatile Metric rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT,
IntervalProperty.INTERVAL);

/**
* Holds statistics of the recent 60 seconds. The windowLengthInMs is deliberately set to 1000 milliseconds,
* meaning each bucket per second, in this way we can get accurate statistics of each second.
*/
private transient Metric rollingCounterInMinute = new ArrayMetric(1000, 60);
private transient Metric rollingCounterInMinute = new ArrayMetric(60, 60 * 1000);

/**
* The counter for thread count.
@@ -142,7 +142,7 @@ public class StatisticNode implements Node {

@Override
public void reset() {
rollingCounterInSecond = new ArrayMetric(1000 / SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL);
rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL);
}

@Override
@@ -158,7 +158,7 @@ public class StatisticNode implements Node {

@Override
public long blockQps() {
return rollingCounterInSecond.block() / IntervalProperty.INTERVAL;
return rollingCounterInSecond.block() / (long) rollingCounterInSecond.getWindowIntervalInSec();
}

@Override
@@ -183,7 +183,7 @@ public class StatisticNode implements Node {

@Override
public long exceptionQps() {
return rollingCounterInSecond.exception() / IntervalProperty.INTERVAL;
return rollingCounterInSecond.exception() / (long) rollingCounterInSecond.getWindowIntervalInSec();
}

@Override
@@ -193,17 +193,17 @@ public class StatisticNode implements Node {

@Override
public long passQps() {
return rollingCounterInSecond.pass() / IntervalProperty.INTERVAL;
return rollingCounterInSecond.pass() / (long) rollingCounterInSecond.getWindowIntervalInSec();
}

@Override
public long successQps() {
return rollingCounterInSecond.success() / IntervalProperty.INTERVAL;
return rollingCounterInSecond.success() / (long) rollingCounterInSecond.getWindowIntervalInSec();
}

@Override
public long maxSuccessQps() {
return rollingCounterInSecond.maxSuccess() * SampleCountProperty.SAMPLE_COUNT;
return rollingCounterInSecond.maxSuccess() * rollingCounterInSecond.getSampleCount();
}

@Override


+ 3
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/RuleConstant.java View File

@@ -51,5 +51,8 @@ public final class RuleConstant {
public static final String LIMIT_APP_DEFAULT = "default";
public static final String LIMIT_APP_OTHER = "other";

public static final int DEFAULT_SAMPLE_COUNT = 2;
public static final int DEFAULT_WINDOW_INTERVAL_MS = 1000;

private RuleConstant() {}
}

+ 20
- 14
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArray.java View File

@@ -54,20 +54,17 @@ public abstract class LeapArray<T> {
/**
* The total bucket count is: {@code sampleCount = intervalInMs / windowLengthInMs}.
*
* @param windowLengthInMs a single window bucket's time length in milliseconds.
* @param intervalInSec the total time span of this {@link LeapArray} in seconds.
* @param sampleCount bucket count of the sliding window
* @param intervalInMs the total time interval of this {@link LeapArray} in milliseconds
*/
public LeapArray(int windowLengthInMs, int intervalInSec) {
// TODO: change `intervalInSec` to `intervalInMs`
AssertUtil.isTrue(windowLengthInMs > 0, "bucket length is invalid: " + windowLengthInMs);
int intervalInMs = intervalInSec * 1000;
AssertUtil.isTrue(intervalInMs > windowLengthInMs,
"total time span of the window should be greater than bucket length");
AssertUtil.isTrue(intervalInMs % windowLengthInMs == 0, "time span needs to be evenly divided");

this.windowLengthInMs = windowLengthInMs;
public LeapArray(int sampleCount, int intervalInMs) {
AssertUtil.isTrue(sampleCount > 0, "bucket count is invalid: " + sampleCount);
AssertUtil.isTrue(intervalInMs > 0, "total time interval of the sliding window should be positive");
AssertUtil.isTrue(intervalInMs % sampleCount == 0, "time span needs to be evenly divided");

this.windowLengthInMs = intervalInMs / sampleCount;
this.intervalInMs = intervalInMs;
this.sampleCount = intervalInMs / windowLengthInMs;
this.sampleCount = sampleCount;

this.array = new AtomicReferenceArray<WindowWrap<T>>(sampleCount);
}
@@ -345,12 +342,21 @@ public abstract class LeapArray<T> {
return sampleCount;
}

/**
* Get total interval length of the sliding window in milliseconds.
*
* @return interval in second
*/
public int getIntervalInMs() {
return intervalInMs;
}

/**
* Get total interval length of the sliding window.
*
* @return interval in second
*/
public int getIntervalInSecond() {
return intervalInMs / 1000;
public double getIntervalInSecond() {
return intervalInMs / 1000.0;
}
}

+ 12
- 6
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/ArrayMetric.java View File

@@ -33,12 +33,8 @@ public class ArrayMetric implements Metric {

private final MetricsLeapArray data;

/**
* @param windowLengthInMs a single window bucket's time length in milliseconds.
* @param intervalInSec the total time span of this {@link ArrayMetric} in seconds.
*/
public ArrayMetric(int windowLengthInMs, int intervalInSec) {
this.data = new MetricsLeapArray(windowLengthInMs, intervalInSec);
public ArrayMetric(int sampleCount, int intervalInMs) {
this.data = new MetricsLeapArray(sampleCount, intervalInMs);
}

/**
@@ -229,4 +225,14 @@ public class ArrayMetric implements Metric {
}
return wrap.value().pass();
}

@Override
public double getWindowIntervalInSec() {
return data.getIntervalInSecond();
}

@Override
public int getSampleCount() {
return data.getSampleCount();
}
}

+ 4
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/Metric.java View File

@@ -118,6 +118,10 @@ public interface Metric {
*/
void addRT(long rt);

double getWindowIntervalInSec();

int getSampleCount();

// Tool methods.

void debugQps();


+ 2
- 6
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/MetricsLeapArray.java View File

@@ -28,12 +28,8 @@ import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap;
*/
public class MetricsLeapArray extends LeapArray<MetricBucket> {

/**
* @param windowLengthInMs a single window bucket's time length in milliseconds.
* @param intervalInSec the total time span of this {@link MetricsLeapArray} in seconds.
*/
public MetricsLeapArray(int windowLengthInMs, int intervalInSec) {
super(windowLengthInMs, intervalInSec);
public MetricsLeapArray(int sampleCount, int intervalInMs) {
super(sampleCount, intervalInMs);
}

@Override


+ 0
- 1
sentinel-core/src/test/java/com/alibaba/csp/sentinel/base/metric/ArrayMetricTest.java View File

@@ -36,7 +36,6 @@ import static org.mockito.Mockito.*;
public class ArrayMetricTest {

private final int windowLengthInMs = 500;
private final int intervalInSec = 1;

@Test
public void testOperateArrayMetric() {


+ 15
- 11
sentinel-core/src/test/java/com/alibaba/csp/sentinel/base/metric/MetricsLeapArrayTest.java View File

@@ -39,10 +39,12 @@ public class MetricsLeapArrayTest {

private final int windowLengthInMs = 1000;
private final int intervalInSec = 2;
private final int intervalInMs = intervalInSec * 1000;
private final int sampleCount = intervalInMs / windowLengthInMs;

@Test
public void testNewWindow() {
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
long time = TimeUtil.currentTimeMillis();
WindowWrap<MetricBucket> window = leapArray.currentWindow(time);

@@ -54,7 +56,7 @@ public class MetricsLeapArrayTest {

@Test
public void testLeapArrayWindowStart() {
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
long firstTime = TimeUtil.currentTimeMillis();
long previousWindowStart = firstTime - firstTime % windowLengthInMs;

@@ -66,7 +68,7 @@ public class MetricsLeapArrayTest {

@Test
public void testWindowAfterOneInterval() {
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
long firstTime = TimeUtil.currentTimeMillis();
long previousWindowStart = firstTime - firstTime % windowLengthInMs;
WindowWrap<MetricBucket> window = leapArray.currentWindow(previousWindowStart);
@@ -106,8 +108,8 @@ public class MetricsLeapArrayTest {

@Deprecated
public void testWindowDeprecatedRefresh() {
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
final int len = intervalInSec * 1000 / windowLengthInMs;
MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
final int len = sampleCount;
long firstTime = TimeUtil.currentTimeMillis();
List<WindowWrap<MetricBucket>> firstIterWindowList = new ArrayList<WindowWrap<MetricBucket>>(len);
for (int i = 0; i < len; i++) {
@@ -126,7 +128,7 @@ public class MetricsLeapArrayTest {
public void testMultiThreadUpdateEmptyWindow() throws Exception {
final long time = TimeUtil.currentTimeMillis();
final int nThreads = 16;
final MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
final MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
final CountDownLatch latch = new CountDownLatch(nThreads);
Runnable task = new Runnable() {
@Override
@@ -147,7 +149,7 @@ public class MetricsLeapArrayTest {

@Test
public void testGetPreviousWindow() {
MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
long time = TimeUtil.currentTimeMillis();
WindowWrap<MetricBucket> previousWindow = leapArray.currentWindow(time);
assertNull(leapArray.getPreviousWindow(time));
@@ -162,10 +164,10 @@ public class MetricsLeapArrayTest {
@Test
public void testListWindowsResetOld() throws Exception {
final int windowLengthInMs = 100;
final int intervalInSec = 1;
final int intervalInMs = intervalInSec * 1000;
final int intervalInMs = 1000;
final int sampleCount = intervalInMs / windowLengthInMs;

MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
long time = TimeUtil.currentTimeMillis();

Set<WindowWrap<MetricBucket>> windowWraps = new HashSet<WindowWrap<MetricBucket>>();
@@ -190,8 +192,10 @@ public class MetricsLeapArrayTest {
public void testListWindowsNewBucket() throws Exception {
final int windowLengthInMs = 100;
final int intervalInSec = 1;
final int intervalInMs = intervalInSec * 1000;
final int sampleCount = intervalInMs / windowLengthInMs;

MetricsLeapArray leapArray = new MetricsLeapArray(windowLengthInMs, intervalInSec);
MetricsLeapArray leapArray = new MetricsLeapArray(sampleCount, intervalInMs);
long time = TimeUtil.currentTimeMillis();

Set<WindowWrap<MetricBucket>> windowWraps = new HashSet<WindowWrap<MetricBucket>>();


+ 3
- 3
sentinel-core/src/test/java/com/alibaba/csp/sentinel/slots/statistic/base/LeapArrayTest.java View File

@@ -29,9 +29,9 @@ public class LeapArrayTest {
@Test
public void testGetValidHead() {
int windowLengthInMs = 100;
int intervalInSec = 1;
int sampleCount = intervalInSec * 1000 / windowLengthInMs;
LeapArray<AtomicInteger> leapArray = new LeapArray<AtomicInteger>(windowLengthInMs, intervalInSec) {
int intervalInMs = 1000;
int sampleCount = intervalInMs / windowLengthInMs;
LeapArray<AtomicInteger> leapArray = new LeapArray<AtomicInteger>(sampleCount, intervalInMs) {
@Override
public AtomicInteger newEmptyBucket() {
return new AtomicInteger(0);


+ 0
- 1
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParamFlowRuleManager.java View File

@@ -16,7 +16,6 @@
package com.alibaba.csp.sentinel.slots.block.flow.param;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


+ 17
- 2
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/param/ParameterMetric.java View File

@@ -25,6 +25,7 @@ import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.node.IntervalProperty;
import com.alibaba.csp.sentinel.node.SampleCountProperty;
import com.alibaba.csp.sentinel.slots.statistic.metric.HotParameterLeapArray;
import com.alibaba.csp.sentinel.util.AssertUtil;

/**
* Metrics for frequent ("hot spot") parameters.
@@ -34,6 +35,21 @@ import com.alibaba.csp.sentinel.slots.statistic.metric.HotParameterLeapArray;
*/
public class ParameterMetric {

private final int sampleCount;
private final int intervalMs;

public ParameterMetric() {
this(SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL);
}

public ParameterMetric(int sampleCount, int intervalInMs) {
AssertUtil.isTrue(sampleCount > 0, "sampleCount should be positive");
AssertUtil.isTrue(intervalInMs > 0, "window interval should be positive");
AssertUtil.isTrue(intervalInMs % sampleCount == 0, "time span needs to be evenly divided");
this.sampleCount = sampleCount;
this.intervalMs = intervalInMs;
}

private Map<Integer, HotParameterLeapArray> rollingParameters =
new ConcurrentHashMap<Integer, HotParameterLeapArray>();

@@ -50,8 +66,7 @@ public class ParameterMetric {
synchronized (this) {
// putIfAbsent
if (rollingParameters.get(index) == null) {
rollingParameters.put(index, new HotParameterLeapArray(
1000 / SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL));
rollingParameters.put(index, new HotParameterLeapArray(sampleCount, intervalMs));
}
}
}


+ 4
- 11
sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/metric/HotParameterLeapArray.java View File

@@ -37,15 +37,8 @@ import com.alibaba.csp.sentinel.slots.statistic.data.ParamMapBucket;
*/
public class HotParameterLeapArray extends LeapArray<ParamMapBucket> {

private int intervalInSec;

public HotParameterLeapArray(int windowLengthInMs, int intervalInSec) {
super(windowLengthInMs, intervalInSec);
this.intervalInSec = intervalInSec;
}

public int getIntervalInSec() {
return intervalInSec;
public HotParameterLeapArray(int sampleCount, int intervalInMs) {
super(sampleCount, intervalInMs);
}

@Override
@@ -116,7 +109,7 @@ public class HotParameterLeapArray extends LeapArray<ParamMapBucket> {
if (x.getValue() == 0) {
break;
}
doubleResult.put(x.getKey(), ((double)x.getValue()) / getIntervalInSec());
doubleResult.put(x.getKey(), ((double)x.getValue()) / getIntervalInSecond());
}

return doubleResult;
@@ -136,6 +129,6 @@ public class HotParameterLeapArray extends LeapArray<ParamMapBucket> {
}

public double getRollingAvg(RollingParamEvent event, Object value) {
return ((double) getRollingSum(event, value)) / getIntervalInSec();
return ((double) getRollingSum(event, value)) / getIntervalInSecond();
}
}

+ 3
- 3
sentinel-extension/sentinel-parameter-flow-control/src/test/java/com/alibaba/csp/sentinel/slots/statistic/metric/HotParameterLeapArrayTest.java View File

@@ -60,7 +60,7 @@ public class HotParameterLeapArrayTest {
int a1 = 3, a2 = 5;
String paramPrefix = "param-";
HotParameterLeapArray leapArray = mock(HotParameterLeapArray.class);
when(leapArray.getIntervalInSec()).thenReturn(intervalInSec);
when(leapArray.getIntervalInSecond()).thenReturn((double) intervalInSec);

final ParamMapBucket b1 = generateBucket(a1, paramPrefix);
final ParamMapBucket b2 = generateBucket(a2, paramPrefix);
@@ -122,8 +122,8 @@ public class HotParameterLeapArrayTest {
public void testGetRollingAvg() {
HotParameterLeapArray leapArray = mock(HotParameterLeapArray.class);
when(leapArray.getRollingSum(any(RollingParamEvent.class), any(Object.class))).thenReturn(15L);
when(leapArray.getIntervalInSec()).thenReturn(1)
.thenReturn(2);
when(leapArray.getIntervalInSecond()).thenReturn(1d)
.thenReturn(2d);
when(leapArray.getRollingAvg(any(RollingParamEvent.class), any(Object.class))).thenCallRealMethod();

assertEquals(15.0d, leapArray.getRollingAvg(RollingParamEvent.REQUEST_PASSED, "abc"), 0.001);


Loading…
Cancel
Save