|
25 | 25 | import org.apache.flink.autoscaler.topology.ShipStrategy;
|
26 | 26 | import org.apache.flink.autoscaler.utils.AutoScalerUtils;
|
27 | 27 | import org.apache.flink.configuration.Configuration;
|
| 28 | +import org.apache.flink.configuration.DescribedEnum; |
| 29 | +import org.apache.flink.configuration.description.InlineElement; |
28 | 30 | import org.apache.flink.runtime.jobgraph.JobVertexID;
|
29 | 31 | import org.apache.flink.util.Preconditions;
|
30 | 32 |
|
|
41 | 43 | import java.util.Objects;
|
42 | 44 | import java.util.SortedMap;
|
43 | 45 |
|
| 46 | +import static org.apache.flink.autoscaler.JobVertexScaler.KeyGroupOrPartitionsAdjustMode.MAXIMIZE_UTILISATION; |
44 | 47 | import static org.apache.flink.autoscaler.config.AutoScalerOptions.MAX_SCALE_DOWN_FACTOR;
|
45 | 48 | import static org.apache.flink.autoscaler.config.AutoScalerOptions.MAX_SCALE_UP_FACTOR;
|
46 | 49 | import static org.apache.flink.autoscaler.config.AutoScalerOptions.SCALE_DOWN_INTERVAL;
|
47 | 50 | import static org.apache.flink.autoscaler.config.AutoScalerOptions.SCALING_EVENT_INTERVAL;
|
| 51 | +import static org.apache.flink.autoscaler.config.AutoScalerOptions.SCALING_KEY_GROUP_PARTITIONS_ADJUST_MODE; |
48 | 52 | import static org.apache.flink.autoscaler.config.AutoScalerOptions.TARGET_UTILIZATION;
|
49 | 53 | import static org.apache.flink.autoscaler.config.AutoScalerOptions.VERTEX_MAX_PARALLELISM;
|
50 | 54 | import static org.apache.flink.autoscaler.config.AutoScalerOptions.VERTEX_MIN_PARALLELISM;
|
|
54 | 58 | import static org.apache.flink.autoscaler.metrics.ScalingMetric.PARALLELISM;
|
55 | 59 | import static org.apache.flink.autoscaler.metrics.ScalingMetric.TRUE_PROCESSING_RATE;
|
56 | 60 | import static org.apache.flink.autoscaler.topology.ShipStrategy.HASH;
|
| 61 | +import static org.apache.flink.configuration.description.TextElement.text; |
57 | 62 | import static org.apache.flink.util.Preconditions.checkArgument;
|
58 | 63 |
|
59 | 64 | /** Component responsible for computing vertex parallelism based on the scaling metrics. */
|
@@ -411,26 +416,29 @@ protected static <KEY, Context extends JobAutoScalerContext<KEY>> int scale(
|
411 | 416 |
|
412 | 417 | var numKeyGroupsOrPartitions =
|
413 | 418 | numSourcePartitions <= 0 ? maxParallelism : numSourcePartitions;
|
414 |
| - var upperBoundForAlignment = |
415 |
| - Math.min( |
416 |
| - // Optimize the case where newParallelism <= maxParallelism / 2 |
417 |
| - newParallelism > numKeyGroupsOrPartitions / 2 |
418 |
| - ? numKeyGroupsOrPartitions |
419 |
| - : numKeyGroupsOrPartitions / 2, |
420 |
| - upperBound); |
| 419 | + var upperBoundForAlignment = Math.min(numKeyGroupsOrPartitions, upperBound); |
| 420 | + |
| 421 | + KeyGroupOrPartitionsAdjustMode mode = |
| 422 | + context.getConfiguration().get(SCALING_KEY_GROUP_PARTITIONS_ADJUST_MODE); |
421 | 423 |
|
422 | 424 | // When the shuffle type of vertex inputs contains keyBy or vertex is a source,
|
423 | 425 | // we try to adjust the parallelism such that it divides
|
424 | 426 | // the numKeyGroupsOrPartitions without a remainder => data is evenly spread across subtasks
|
425 | 427 | for (int p = newParallelism; p <= upperBoundForAlignment; p++) {
|
426 |
| - if (numKeyGroupsOrPartitions % p == 0) { |
| 428 | + if (numKeyGroupsOrPartitions % p == 0 |
| 429 | + || |
| 430 | + // When Mode is MAXIMIZE_UTILISATION , Try to find the smallest parallelism |
| 431 | + // that can satisfy the current consumption rate. |
| 432 | + (mode == MAXIMIZE_UTILISATION |
| 433 | + && numKeyGroupsOrPartitions / p |
| 434 | + < numKeyGroupsOrPartitions / newParallelism)) { |
427 | 435 | return p;
|
428 | 436 | }
|
429 | 437 | }
|
430 | 438 |
|
431 |
| - // When adjust the parallelism after rounding up cannot be evenly divided by |
432 |
| - // numKeyGroupsOrPartitions, Try to find the smallest parallelism that can satisfy the |
433 |
| - // current consumption rate. |
| 439 | + // When adjusting the parallelism after rounding up cannot |
| 440 | + // find the parallelism to meet requirements. |
| 441 | + // Try to find the smallest parallelism that can satisfy the current consumption rate. |
434 | 442 | int p = newParallelism;
|
435 | 443 | for (; p > 0; p--) {
|
436 | 444 | if (numKeyGroupsOrPartitions / p > numKeyGroupsOrPartitions / newParallelism) {
|
@@ -465,4 +473,29 @@ protected static <KEY, Context extends JobAutoScalerContext<KEY>> int scale(
|
465 | 473 | protected void setClock(Clock clock) {
|
466 | 474 | this.clock = Preconditions.checkNotNull(clock);
|
467 | 475 | }
|
| 476 | + |
| 477 | + /** The mode of the key group or parallelism adjustment. */ |
| 478 | + public enum KeyGroupOrPartitionsAdjustMode implements DescribedEnum { |
| 479 | + EVENLY_SPREAD( |
| 480 | + "This mode ensures that the parallelism adjustment attempts to evenly distribute data across subtasks" |
| 481 | + + ". It is particularly effective for source vertices that are aware of partition counts or vertices after " |
| 482 | + + "'keyBy' operation. The goal is to have the number of key groups or partitions be divisible by the set parallelism, ensuring even data distribution and reducing data skew."), |
| 483 | + |
| 484 | + MAXIMIZE_UTILISATION( |
| 485 | + "This model is to maximize resource utilization. In this mode, an attempt is made to set" |
| 486 | + + " the parallelism that meets the current consumption rate requirements. It is not enforced " |
| 487 | + + "that the number of key groups or partitions is divisible by the parallelism."), |
| 488 | + ; |
| 489 | + |
| 490 | + private final InlineElement description; |
| 491 | + |
| 492 | + KeyGroupOrPartitionsAdjustMode(String description) { |
| 493 | + this.description = text(description); |
| 494 | + } |
| 495 | + |
| 496 | + @Override |
| 497 | + public InlineElement getDescription() { |
| 498 | + return description; |
| 499 | + } |
| 500 | + } |
468 | 501 | }
|
0 commit comments