Skip to content

Commit b33622a

Browse files
author
Matt Jacobs
committed
Make values for HystrixRollingPercentile bucket calculation only affect construction, and never runtime.
* This deprecates a constructor that accepted HystrixProperty<Integer> for these properties in favor of a new one, which accepts ints
1 parent 793d366 commit b33622a

File tree

5 files changed

+56
-31
lines changed

5 files changed

+56
-31
lines changed

hystrix-core/src/jmh/java/com/netflix/hystrix/perf/RollingPercentilePerfTest.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@ public static class PercentileState {
2727

2828
@Setup(Level.Iteration)
2929
public void setUp() {
30-
percentile = new HystrixRollingPercentile(
31-
HystrixProperty.Factory.asProperty(100),
32-
HystrixProperty.Factory.asProperty(10),
33-
HystrixProperty.Factory.asProperty(1000),
34-
HystrixProperty.Factory.asProperty(percentileEnabled));
30+
percentile = new HystrixRollingPercentile(100, 10, 1000, HystrixProperty.Factory.asProperty(percentileEnabled));
3531
}
3632
}
3733

hystrix-core/src/main/java/com/netflix/hystrix/HystrixCollapserMetrics.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ public static Collection<HystrixCollapserMetrics> getInstances() {
9292
this.key = key;
9393
this.properties = properties;
9494

95-
this.percentileBatchSize = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds(), properties.metricsRollingPercentileWindowBuckets(), properties.metricsRollingPercentileBucketSize(), properties.metricsRollingPercentileEnabled());
96-
this.percentileShardSize = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds(), properties.metricsRollingPercentileWindowBuckets(), properties.metricsRollingPercentileBucketSize(), properties.metricsRollingPercentileEnabled());
95+
this.percentileBatchSize = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds().get(), properties.metricsRollingPercentileWindowBuckets().get(), properties.metricsRollingPercentileBucketSize().get(), properties.metricsRollingPercentileEnabled());
96+
this.percentileShardSize = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds().get(), properties.metricsRollingPercentileWindowBuckets().get(), properties.metricsRollingPercentileBucketSize().get(), properties.metricsRollingPercentileEnabled());
9797
}
9898

9999
/**

hystrix-core/src/main/java/com/netflix/hystrix/HystrixCommandMetrics.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ public static Collection<HystrixCommandMetrics> getInstances() {
142142
this.group = commandGroup;
143143
this.threadPoolKey = threadPoolKey;
144144
this.properties = properties;
145-
this.percentileExecution = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds(), properties.metricsRollingPercentileWindowBuckets(), properties.metricsRollingPercentileBucketSize(), properties.metricsRollingPercentileEnabled());
146-
this.percentileTotal = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds(), properties.metricsRollingPercentileWindowBuckets(), properties.metricsRollingPercentileBucketSize(), properties.metricsRollingPercentileEnabled());
145+
this.percentileExecution = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds().get(), properties.metricsRollingPercentileWindowBuckets().get(), properties.metricsRollingPercentileBucketSize().get(), properties.metricsRollingPercentileEnabled());
146+
this.percentileTotal = new HystrixRollingPercentile(properties.metricsRollingPercentileWindowInMilliseconds().get(), properties.metricsRollingPercentileWindowBuckets().get(), properties.metricsRollingPercentileBucketSize().get(), properties.metricsRollingPercentileEnabled());
147147
this.eventNotifier = eventNotifier;
148148
}
149149

hystrix-core/src/main/java/com/netflix/hystrix/util/HystrixRollingPercentile.java

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ public class HystrixRollingPercentile {
4949
private static final Time ACTUAL_TIME = new ActualTime();
5050
private final Time time;
5151
/* package for testing */ final BucketCircularArray buckets;
52-
private final HystrixProperty<Integer> timeInMilliseconds;
53-
private final HystrixProperty<Integer> numberOfBuckets;
54-
private final HystrixProperty<Integer> bucketDataLength;
52+
private final int timeInMilliseconds;
53+
private final int numberOfBuckets;
54+
private final int bucketDataLength;
55+
private final int bucketSizeInMilliseconds;
5556
private final HystrixProperty<Boolean> enabled;
5657

5758
/*
@@ -62,39 +63,71 @@ public class HystrixRollingPercentile {
6263
/**
6364
*
6465
* @param timeInMilliseconds
65-
* {@code HystrixProperty<Integer>} for nummber of milliseconds of data that should be tracked
66+
* {@code HystrixProperty<Integer>} for number of milliseconds of data that should be tracked
67+
* Note that this value is represented as a {@link HystrixProperty}, but can not actually be modified
68+
* at runtime, to avoid data loss
6669
* <p>
6770
* Example: 60000 for 1 minute
6871
* @param numberOfBuckets
6972
* {@code HystrixProperty<Integer>} for number of buckets that the time window should be divided into
73+
* Note that this value is represented as a {@link HystrixProperty}, but can not actually be modified
74+
* at runtime, to avoid data loss
7075
* <p>
7176
* Example: 12 for 5 second buckets in a 1 minute window
7277
* @param bucketDataLength
7378
* {@code HystrixProperty<Integer>} for number of values stored in each bucket
79+
* Note that this value is represented as a {@link HystrixProperty}, but can not actually be modified
80+
* at runtime, to avoid data loss
7481
* <p>
7582
* Example: 1000 to store a max of 1000 values in each 5 second bucket
7683
* @param enabled
7784
* {@code HystrixProperty<Boolean>} whether data should be tracked and percentiles calculated.
7885
* <p>
7986
* If 'false' methods will do nothing.
87+
* @deprecated Please use the constructor with non-configurable properties {@link HystrixRollingPercentile(Time, int, int, int, HystrixProperty<Boolean>}
8088
*/
89+
@Deprecated
8190
public HystrixRollingPercentile(HystrixProperty<Integer> timeInMilliseconds, HystrixProperty<Integer> numberOfBuckets, HystrixProperty<Integer> bucketDataLength, HystrixProperty<Boolean> enabled) {
91+
this(timeInMilliseconds.get(), numberOfBuckets.get(), bucketDataLength.get(), enabled);
92+
}
93+
94+
/**
95+
*
96+
* @param timeInMilliseconds
97+
* number of milliseconds of data that should be tracked
98+
* <p>
99+
* Example: 60000 for 1 minute
100+
* @param numberOfBuckets
101+
* number of buckets that the time window should be divided into
102+
* <p>
103+
* Example: 12 for 5 second buckets in a 1 minute window
104+
* @param bucketDataLength
105+
* number of values stored in each bucket
106+
* <p>
107+
* Example: 1000 to store a max of 1000 values in each 5 second bucket
108+
* @param enabled
109+
* {@code HystrixProperty<Boolean>} whether data should be tracked and percentiles calculated.
110+
* <p>
111+
* If 'false' methods will do nothing.
112+
*/
113+
public HystrixRollingPercentile(int timeInMilliseconds, int numberOfBuckets, int bucketDataLength, HystrixProperty<Boolean> enabled) {
82114
this(ACTUAL_TIME, timeInMilliseconds, numberOfBuckets, bucketDataLength, enabled);
83115

84116
}
85117

86-
/* package for testing */ HystrixRollingPercentile(Time time, HystrixProperty<Integer> timeInMilliseconds, HystrixProperty<Integer> numberOfBuckets, HystrixProperty<Integer> bucketDataLength, HystrixProperty<Boolean> enabled) {
118+
/* package for testing */ HystrixRollingPercentile(Time time, int timeInMilliseconds, int numberOfBuckets, int bucketDataLength, HystrixProperty<Boolean> enabled) {
87119
this.time = time;
88120
this.timeInMilliseconds = timeInMilliseconds;
89121
this.numberOfBuckets = numberOfBuckets;
90122
this.bucketDataLength = bucketDataLength;
91123
this.enabled = enabled;
92124

93-
if (this.timeInMilliseconds.get() % this.numberOfBuckets.get() != 0) {
125+
if (this.timeInMilliseconds % this.numberOfBuckets != 0) {
94126
throw new IllegalArgumentException("The timeInMilliseconds must divide equally into numberOfBuckets. For example 1000/10 is ok, 1000/11 is not.");
95127
}
128+
this.bucketSizeInMilliseconds = this.timeInMilliseconds / this.numberOfBuckets;
96129

97-
buckets = new BucketCircularArray(this.numberOfBuckets.get());
130+
buckets = new BucketCircularArray(this.numberOfBuckets);
98131
}
99132

100133
/**
@@ -166,10 +199,6 @@ private PercentileSnapshot getCurrentPercentileSnapshot() {
166199
return currentPercentileSnapshot;
167200
}
168201

169-
private int getBucketSizeInMilliseconds() {
170-
return timeInMilliseconds.get() / numberOfBuckets.get();
171-
}
172-
173202
private ReentrantLock newBucketLock = new ReentrantLock();
174203

175204
private Bucket getCurrentBucket() {
@@ -183,7 +212,7 @@ private Bucket getCurrentBucket() {
183212
* NOTE: This is thread-safe because it's accessing 'buckets' which is a LinkedBlockingDeque
184213
*/
185214
Bucket currentBucket = buckets.peekLast();
186-
if (currentBucket != null && currentTime < currentBucket.windowStart + getBucketSizeInMilliseconds()) {
215+
if (currentBucket != null && currentTime < currentBucket.windowStart + this.bucketSizeInMilliseconds) {
187216
// if we're within the bucket 'window of time' return the current one
188217
// NOTE: We do not worry if we are BEFORE the window in a weird case of where thread scheduling causes that to occur,
189218
// we'll just use the latest as long as we're not AFTER the window
@@ -218,29 +247,29 @@ private Bucket getCurrentBucket() {
218247
try {
219248
if (buckets.peekLast() == null) {
220249
// the list is empty so create the first bucket
221-
Bucket newBucket = new Bucket(currentTime, bucketDataLength.get());
250+
Bucket newBucket = new Bucket(currentTime, bucketDataLength);
222251
buckets.addLast(newBucket);
223252
return newBucket;
224253
} else {
225254
// We go into a loop so that it will create as many buckets as needed to catch up to the current time
226255
// as we want the buckets complete even if we don't have transactions during a period of time.
227-
for (int i = 0; i < numberOfBuckets.get(); i++) {
256+
for (int i = 0; i < numberOfBuckets; i++) {
228257
// we have at least 1 bucket so retrieve it
229258
Bucket lastBucket = buckets.peekLast();
230-
if (currentTime < lastBucket.windowStart + getBucketSizeInMilliseconds()) {
259+
if (currentTime < lastBucket.windowStart + this.bucketSizeInMilliseconds) {
231260
// if we're within the bucket 'window of time' return the current one
232261
// NOTE: We do not worry if we are BEFORE the window in a weird case of where thread scheduling causes that to occur,
233262
// we'll just use the latest as long as we're not AFTER the window
234263
return lastBucket;
235-
} else if (currentTime - (lastBucket.windowStart + getBucketSizeInMilliseconds()) > timeInMilliseconds.get()) {
264+
} else if (currentTime - (lastBucket.windowStart + this.bucketSizeInMilliseconds) > timeInMilliseconds) {
236265
// the time passed is greater than the entire rolling counter so we want to clear it all and start from scratch
237266
reset();
238267
// recursively call getCurrentBucket which will create a new bucket and return it
239268
return getCurrentBucket();
240269
} else { // we're past the window so we need to create a new bucket
241270
Bucket[] allBuckets = buckets.getArray();
242271
// create a new bucket and add it as the new 'last' (once this is done other threads will start using it on subsequent retrievals)
243-
buckets.addLast(new Bucket(lastBucket.windowStart + getBucketSizeInMilliseconds(), bucketDataLength.get()));
272+
buckets.addLast(new Bucket(lastBucket.windowStart + this.bucketSizeInMilliseconds, bucketDataLength));
244273
// we created a new bucket so let's re-generate the PercentileSnapshot (not including the new bucket)
245274
currentPercentileSnapshot = new PercentileSnapshot(allBuckets);
246275
}

hystrix-core/src/test/java/com/netflix/hystrix/util/HystrixRollingPercentileTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@
3737

3838
public class HystrixRollingPercentileTest {
3939

40-
private static final HystrixProperty<Integer> timeInMilliseconds = HystrixProperty.Factory.asProperty(60000);
41-
private static final HystrixProperty<Integer> numberOfBuckets = HystrixProperty.Factory.asProperty(12); // 12 buckets at 5000ms each
42-
private static final HystrixProperty<Integer> bucketDataLength = HystrixProperty.Factory.asProperty(1000);
40+
private static final int timeInMilliseconds = 60000;
41+
private static final int numberOfBuckets = 12; // 12 buckets at 5000ms each
42+
private static final int bucketDataLength = 1000;
4343
private static final HystrixProperty<Boolean> enabled = HystrixProperty.Factory.asProperty(true);
4444

4545
private static ExecutorService threadPool;
@@ -356,7 +356,7 @@ public void testDoesNothingWhenDisabled() {
356356
@Test
357357
public void testThreadSafety() {
358358
final MockedTime time = new MockedTime();
359-
final HystrixRollingPercentile p = new HystrixRollingPercentile(time, HystrixProperty.Factory.asProperty(100), HystrixProperty.Factory.asProperty(25), HystrixProperty.Factory.asProperty(1000), HystrixProperty.Factory.asProperty(true));
359+
final HystrixRollingPercentile p = new HystrixRollingPercentile(time, 100, 25, 1000, HystrixProperty.Factory.asProperty(true));
360360

361361
final int NUM_THREADS = 1000;
362362
final int NUM_ITERATIONS = 1000000;
@@ -408,7 +408,7 @@ public void run() {
408408
@Test
409409
public void testWriteThreadSafety() {
410410
final MockedTime time = new MockedTime();
411-
final HystrixRollingPercentile p = new HystrixRollingPercentile(time, HystrixProperty.Factory.asProperty(100), HystrixProperty.Factory.asProperty(25), HystrixProperty.Factory.asProperty(1000), HystrixProperty.Factory.asProperty(true));
411+
final HystrixRollingPercentile p = new HystrixRollingPercentile(time, 100, 25, 1000, HystrixProperty.Factory.asProperty(true));
412412

413413
final int NUM_THREADS = 10;
414414
final int NUM_ITERATIONS = 1000;

0 commit comments

Comments
 (0)