close
Skip to content

[Improve][Zeta] Improve job metrics handling with partitioning support#9833

Merged
zhangshenghang merged 12 commits into
apache:devfrom
dybyte:improve/metrics-imap
Sep 11, 2025
Merged

[Improve][Zeta] Improve job metrics handling with partitioning support#9833
zhangshenghang merged 12 commits into
apache:devfrom
dybyte:improve/metrics-imap

Conversation

@dybyte

@dybyte dybyte commented Sep 6, 2025

Copy link
Copy Markdown
Contributor

Fixes #9817

Purpose of this pull request

This PR introduces a new configuration option JOB_METRICS_PARTITION_COUNT which controls the number of partitions used to store running job metrics in Hazelcast IMap. This allows distributing metrics across multiple keys to reduce contention and improve performance when multiple tasks report metrics concurrently.

If you prefer to use a single key for storing metrics, set JOB_METRICS_PARTITION_COUNT to 1 (this is the default, so no configuration is required).
For better parallelism under high load, you can increase this value.
However, setting it too high may introduce overhead when aggregating metrics across multiple partitions, which can lead to reduced overall performance.

Does this PR introduce any user-facing change?

Yes. Users can tune JOB_METRICS_PARTITION_COUNT to balance write contention and aggregation overhead. Default is 1 for backward compatibility.

How was this patch tested?

  • Current tests verify that metricsImap is updated and cleared with a custom partition configuration.

  • Performance comparison of updateMetrics:

partitionCount: 1
Average completion time per op: 33.461999 seconds
Distributed metrics performance:
- ops: 100, seconds: 119.766, ops/s: 1
----
partitionCount: 10
Average completion time per op: 30.051322 seconds
Distributed metrics performance:
- ops: 100, seconds: 113.089, ops/s: 1
----
partitionCount: 50
Average completion time per op: 24.181994 seconds
Distributed metrics performance:
- ops: 100, seconds: 88.389, ops/s: 1
----
partitionCount: 1000
Average completion time per op: 20.029176 seconds
Distributed metrics performance:
- ops: 100, seconds: 71.765, ops/s: 1
----
partitionCount: 2000
Average completion time per op: 26.631462 seconds
Distributed metrics performance:
- ops: 100, seconds: 94.996, ops/s: 1
----
Without using partition key(i.e., the previous synchronous approach):
- Average completion time per op: 48.34 seconds
- Total time for 100 ops: 176.83 seconds
- Throughput: 1 ops/sec

Using multiple partitions significantly reduces lock contention, improving the performance of the updateMetrics method. This demonstrates that the multi-key approach performs better than the single-key approach under high concurrency (in a local test).

Check list

@github-actions github-actions Bot added the Zeta label Sep 6, 2025
@dybyte

dybyte commented Sep 6, 2025

Copy link
Copy Markdown
Contributor Author

I was planning to document this new configuration option, but I couldn't find the relevant section for master server config options. Could you please point me to where this should be documented? @Hisoka-X

@dybyte

dybyte commented Sep 6, 2025

Copy link
Copy Markdown
Contributor Author

I am not yet very experienced with performance metrics, so I did not include specific measurements in this PR. However, I can provide benchmarks or metrics if needed—please let me know if you’d like to see them.

@dybyte dybyte marked this pull request as draft September 6, 2025 16:14
@Hisoka-X

Hisoka-X commented Sep 7, 2025

Copy link
Copy Markdown
Member

@dybyte dybyte marked this pull request as ready for review September 8, 2025 01:50
@qiaoborui

Copy link
Copy Markdown

By the way, is there a solution for the current issue of runningJobMetrics growing indefinitely? When synchronizing tasks involving several thousand tables, the WAL persisted in OSS frequently reaches hundreds of GB.
@Hisoka-X

@dybyte

dybyte commented Sep 8, 2025

Copy link
Copy Markdown
Contributor Author

Hi @qiaoborui , Thanks for raising this important point!

My understanding is that the root cause is removeMetrics not executing properly due to heavy contention on the single key.
As a result, finished job metrics were not cleared in time, which caused runningJobMetrics to grow indefinitely.

With this PR, since metrics are partitioned, lock contention should be significantly reduced, so removeMetrics is expected to work more efficiently.
This may help prevent runningJobMetrics from growing indefinitely, even under heavy load.

I’ll keep monitoring this behavior, and if you have further feedback or see this problem persist, please let me know!

@zhangshenghang

Copy link
Copy Markdown
Member

Can we provide a best practice to guide customers in configuration, such as recommended calculation formulas

@Hisoka-X

Hisoka-X commented Sep 8, 2025

Copy link
Copy Markdown
Member

By the way, is there a solution for the current issue of runningJobMetrics growing indefinitely? When synchronizing tasks involving several thousand tables, the WAL persisted in OSS frequently reaches hundreds of GB. @Hisoka-X

@qiaoborui We almost fix it in #9696 and #9776. This PR is only to address potential risks in extreme scenarios.

@dybyte

dybyte commented Sep 9, 2025

Copy link
Copy Markdown
Contributor Author

Can we provide a best practice to guide customers in configuration, such as recommended calculation formulas

@zhangshenghang
Based on local performance tests, increasing the partition count provides significant benefits when the number of tasks exceeds approximately 20,000.
As a practical guideline, a partition count of around 1,000-2,000 tends to offer the best balance between reducing lock contention and minimizing overhead.
It is recommended to start with this value and then adjust based on your cluster size and workload characteristics.
Please note that these recommendations are based on my test results, and the optimal values may vary depending on your environment.

@zhangshenghang

Copy link
Copy Markdown
Member

Can we provide a best practice to guide customers in configuration, such as recommended calculation formulas

@zhangshenghang Based on local performance tests, increasing the partition count provides significant benefits when the number of tasks exceeds approximately 20,000. As a practical guideline, a partition count of around 2,000 tends to offer the best balance between reducing lock contention and minimizing overhead. It is recommended to start with this value and then adjust based on your cluster size and workload characteristics. Please note that these recommendations are based on my test results, and the optimal values may vary depending on your environment.

@dybyte Thanks, you can include it in the document for reference by others. This makes it more convenient for users to use.

@dybyte

dybyte commented Sep 9, 2025

Copy link
Copy Markdown
Contributor Author

@zhangshenghang Thanks, I've added it to the documentation for everyone’s reference.
Let me know if there’s anything else to improve!

@qiaoborui

Copy link
Copy Markdown

Can we provide a best practice to guide customers in configuration, such as recommended calculation formulas

@zhangshenghang Based on local performance tests, increasing the partition count provides significant benefits when the number of tasks exceeds approximately 20,000. As a practical guideline, a partition count of around 1,000-2,000 tends to offer the best balance between reducing lock contention and minimizing overhead. It is recommended to start with this value and then adjust based on your cluster size and workload characteristics. Please note that these recommendations are based on my test results, and the optimal values may vary depending on your environment.

Thank you for pointing this out. I've been keeping an eye on this issue recently as well. However, I previously reviewed these two PRs and noticed that the memory leaks addressed were related to RunningJobStateIMap and pendingJobMasterMap. I didn't observe any changes concerning RunningJobMetrics. Nevertheless, I'll give the latest PRs modifying the IMaps a try. Thank you very much for your contributions.

Comment on lines +382 to +401
for (Map.Entry<Long, Map<TaskLocation, SeaTunnelMetricsContext>> entry :
metricsImap.entrySet()) {
long partition = entry.getKey();
List<TaskLocation> tasksToRemove =
entry.getValue().keySet().stream()
.filter(
t ->
t.getTaskGroupLocation()
.getPipelineLocation()
.equals(pipelineLocation))
.collect(Collectors.toList());
if (!tasksToRemove.isEmpty()) {
partitionedTasks.put(partition, tasksToRemove);
}
}

List<TaskLocation> taskLocations = getTaskLocations(pipelineLocation, centralMap);
taskLocations.forEach(centralMap::remove);
metricsImap.put(Constant.IMAP_RUNNING_JOB_METRICS_KEY, centralMap);
partitionedTasks
.entrySet()
.parallelStream()
.forEach(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why foreach metricsImap twice? Can we use only once?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally separated the logic into two iterations.
The first pass filters tasks outside of metricsImap to minimize the time holding its internal resources,
and the second pass performs only the minimal compute operations inside the metricsImap.
Since write operations are frequent, I believe this approach can help reduce contention.
I’d be happy to adjust the implementation if you feel a single iteration would be more appropriate.

@Hisoka-X Hisoka-X Sep 11, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are a bit limited by imap, maybe we should switch to rocksdb in the future. #9851

@zhangshenghang zhangshenghang merged commit 8eb2b14 into apache:dev Sep 11, 2025
5 checks passed
LeonYoah pushed a commit to LeonYoah/seatunnel that referenced this pull request Sep 27, 2025
@dybyte dybyte deleted the improve/metrics-imap branch October 20, 2025 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] seatunnel2.3.8使用restFulApi提交离线任务,服务部署成功运行一段时间后离线任务执行速度会越来越慢

4 participants