|
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