Skip to content

Commit db578c8

Browse files
committed
[FLINK-36863][autoscaler] Use the maximum parallelism in the past scale-down.interval window when scaling down
1 parent d9e8cce commit db578c8

File tree

3 files changed

+84
-19
lines changed

3 files changed

+84
-19
lines changed

flink-autoscaler/src/main/java/org/apache/flink/autoscaler/DelayedScaleDown.java

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,78 @@
3030

3131
import java.time.Instant;
3232
import java.util.HashMap;
33+
import java.util.LinkedList;
3334
import java.util.Map;
3435

36+
import static org.apache.flink.util.Preconditions.checkState;
37+
3538
/** All delayed scale down requests. */
3639
public class DelayedScaleDown {
3740

41+
@Data
42+
private static class RecommendedParallelism {
43+
@Nonnull private final Instant triggerTime;
44+
private final int parallelism;
45+
46+
@JsonCreator
47+
public RecommendedParallelism(
48+
@Nonnull @JsonProperty("triggerTime") Instant triggerTime,
49+
@JsonProperty("parallelism") int parallelism) {
50+
this.triggerTime = triggerTime;
51+
this.parallelism = parallelism;
52+
}
53+
}
54+
3855
/** The delayed scale down info for vertex. */
3956
@Data
4057
public static class VertexDelayedScaleDownInfo {
4158
private final Instant firstTriggerTime;
42-
private int maxRecommendedParallelism;
59+
// TODO : add the comment to explain how to calculate the max parallelism within the sliding
60+
// window.
61+
private final LinkedList<RecommendedParallelism> recommendedParallelisms;
62+
63+
public VertexDelayedScaleDownInfo(Instant firstTriggerTime) {
64+
this.firstTriggerTime = firstTriggerTime;
65+
this.recommendedParallelisms = new LinkedList<>();
66+
}
4367

4468
@JsonCreator
4569
public VertexDelayedScaleDownInfo(
4670
@JsonProperty("firstTriggerTime") Instant firstTriggerTime,
47-
@JsonProperty("maxRecommendedParallelism") int maxRecommendedParallelism) {
71+
@JsonProperty("recommendedParallelisms")
72+
LinkedList<RecommendedParallelism> recommendedParallelisms) {
4873
this.firstTriggerTime = firstTriggerTime;
49-
this.maxRecommendedParallelism = maxRecommendedParallelism;
74+
this.recommendedParallelisms = recommendedParallelisms;
75+
}
76+
77+
/** Record current recommended parallelism. */
78+
public void recordRecommendedParallelism(Instant triggerTime, int parallelism) {
79+
80+
// Remove all recommended parallelisms that are lower than the latest parallelism.
81+
while (!recommendedParallelisms.isEmpty()
82+
&& recommendedParallelisms.peekLast().getParallelism() <= parallelism) {
83+
recommendedParallelisms.pollLast();
84+
}
85+
86+
recommendedParallelisms.addLast(new RecommendedParallelism(triggerTime, parallelism));
87+
}
88+
89+
@JsonIgnore
90+
public int getMaxRecommendedParallelism(Instant windowStartTime) {
91+
// Remove all recommended parallelisms before the window start time.
92+
while (!recommendedParallelisms.isEmpty()
93+
&& recommendedParallelisms
94+
.peekFirst()
95+
.getTriggerTime()
96+
.isBefore(windowStartTime)) {
97+
recommendedParallelisms.pollFirst();
98+
}
99+
100+
var maxRecommendedParallelism = recommendedParallelisms.peekFirst();
101+
checkState(
102+
maxRecommendedParallelism != null,
103+
"The getMaxRecommendedParallelism should be called after triggering a scale down, it may be a bug.");
104+
return maxRecommendedParallelism.getParallelism();
50105
}
51106
}
52107

@@ -64,17 +119,16 @@ public DelayedScaleDown() {
64119
@Nonnull
65120
public VertexDelayedScaleDownInfo triggerScaleDown(
66121
JobVertexID vertex, Instant triggerTime, int parallelism) {
122+
// The vertexDelayedScaleDownInfo is updated once scale down is triggered due to we need
123+
// update the triggerTime each time.
124+
updated = true;
125+
67126
var vertexDelayedScaleDownInfo = delayedVertices.get(vertex);
68127
if (vertexDelayedScaleDownInfo == null) {
69-
// It's the first trigger
70-
vertexDelayedScaleDownInfo = new VertexDelayedScaleDownInfo(triggerTime, parallelism);
128+
vertexDelayedScaleDownInfo = new VertexDelayedScaleDownInfo(triggerTime);
71129
delayedVertices.put(vertex, vertexDelayedScaleDownInfo);
72-
updated = true;
73-
} else if (parallelism > vertexDelayedScaleDownInfo.getMaxRecommendedParallelism()) {
74-
// Not the first trigger, but the maxRecommendedParallelism needs to be updated.
75-
vertexDelayedScaleDownInfo.setMaxRecommendedParallelism(parallelism);
76-
updated = true;
77130
}
131+
vertexDelayedScaleDownInfo.recordRecommendedParallelism(triggerTime, parallelism);
78132

79133
return vertexDelayedScaleDownInfo;
80134
}

flink-autoscaler/src/main/java/org/apache/flink/autoscaler/JobVertexScaler.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,11 @@ private ParallelismChange applyScaleDownInterval(
278278
}
279279

280280
var now = clock.instant();
281+
var windowStartTime = now.minus(scaleDownInterval);
281282
var delayedScaleDownInfo = delayedScaleDown.triggerScaleDown(vertex, now, newParallelism);
282283

283284
// Never scale down within scale down interval
284-
if (now.isBefore(delayedScaleDownInfo.getFirstTriggerTime().plus(scaleDownInterval))) {
285+
if (windowStartTime.isBefore(delayedScaleDownInfo.getFirstTriggerTime())) {
285286
if (now.equals(delayedScaleDownInfo.getFirstTriggerTime())) {
286287
LOG.info("The scale down of {} is delayed by {}.", vertex, scaleDownInterval);
287288
} else {
@@ -293,7 +294,8 @@ private ParallelismChange applyScaleDownInterval(
293294
} else {
294295
// Using the maximum parallelism within the scale down interval window instead of the
295296
// latest parallelism when scaling down
296-
return ParallelismChange.build(delayedScaleDownInfo.getMaxRecommendedParallelism());
297+
return ParallelismChange.build(
298+
delayedScaleDownInfo.getMaxRecommendedParallelism(windowStartTime));
297299
}
298300
}
299301

flink-autoscaler/src/test/java/org/apache/flink/autoscaler/DelayedScaleDownTest.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,49 @@ void testTriggerUpdateAndClean() {
3838

3939
// First trigger time as the trigger time, and it won't be updated.
4040
assertVertexDelayedScaleDownInfo(
41-
delayedScaleDown.triggerScaleDown(vertex, instant, 5), instant, 5);
41+
delayedScaleDown.triggerScaleDown(vertex, instant, 5), instant, 5, instant);
4242
assertThat(delayedScaleDown.isUpdated()).isTrue();
4343

4444
// The lower parallelism doesn't update the result
4545
assertVertexDelayedScaleDownInfo(
46-
delayedScaleDown.triggerScaleDown(vertex, instant.plusSeconds(5), 3), instant, 5);
46+
delayedScaleDown.triggerScaleDown(vertex, instant.plusSeconds(5), 3),
47+
instant,
48+
5,
49+
instant);
4750

4851
// The higher parallelism will update the result
4952
assertVertexDelayedScaleDownInfo(
50-
delayedScaleDown.triggerScaleDown(vertex, instant.plusSeconds(10), 8), instant, 8);
53+
delayedScaleDown.triggerScaleDown(vertex, instant.plusSeconds(10), 8),
54+
instant,
55+
8,
56+
instant);
5157

5258
// The scale down could be re-triggered again after clean
5359
delayedScaleDown.clearVertex(vertex);
5460
assertThat(delayedScaleDown.getDelayedVertices()).isEmpty();
5561
assertVertexDelayedScaleDownInfo(
5662
delayedScaleDown.triggerScaleDown(vertex, instant.plusSeconds(15), 4),
5763
instant.plusSeconds(15),
58-
4);
64+
4,
65+
instant);
5966

6067
// The scale down could be re-triggered again after cleanAll
6168
delayedScaleDown.clearAll();
6269
assertThat(delayedScaleDown.getDelayedVertices()).isEmpty();
6370
assertVertexDelayedScaleDownInfo(
6471
delayedScaleDown.triggerScaleDown(vertex, instant.plusSeconds(15), 2),
6572
instant.plusSeconds(15),
66-
2);
73+
2,
74+
instant);
6775
}
6876

6977
void assertVertexDelayedScaleDownInfo(
7078
DelayedScaleDown.VertexDelayedScaleDownInfo vertexDelayedScaleDownInfo,
7179
Instant expectedTriggerTime,
72-
int expectedMaxRecommendedParallelism) {
80+
int expectedMaxRecommendedParallelism,
81+
Instant windowStartTime) {
7382
assertThat(vertexDelayedScaleDownInfo.getFirstTriggerTime()).isEqualTo(expectedTriggerTime);
74-
assertThat(vertexDelayedScaleDownInfo.getMaxRecommendedParallelism())
83+
assertThat(vertexDelayedScaleDownInfo.getMaxRecommendedParallelism(windowStartTime))
7584
.isEqualTo(expectedMaxRecommendedParallelism);
7685
}
7786
}

0 commit comments

Comments
 (0)