apache / apache/parquet-java

Excessive synchronization in MemoryManager

オープン
#2,860 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
Component: Hadoop Component: Parquet Priority: Major Type: bug
主要言語
Java
スター
3.1k
フォーク
1.6k
平均マージ
3日 12時間
マージ済み PR(30日)
33

説明

Issue originally reported in Spark: https://issues.apache.org/jira/browse/SPARK-44003

We have a pyspark job that writes to a partitioned parquet dataset via:

```python

df.write.parquet(
path=path,
compression="snappy",
mode="overwrite",
partitionBy="year",
)
```

In this specific production case we partition by 28 distinct years, so 28 directories, each directory with 200 part files, total of 5.6K files. This particular job runs on a single dedicated and ephemeral VM. We have noticed that most of the time the VM is far from being saturated and the job is very slow. It's not IO or CPU bound. Here's an [annotated VM utilization graph ](https://gist.githubusercontent.com/ravwojdyla/e468bace2bc899f86348dee067173270/raw/03cfb383d49ad43adaec2eaa3d9cbf0a3c9b8c0b/VM_util.png). The blue line is CPU, and turquoise is memory. This graph doesn't show IO, but we have also monitored that, and it also was not saturated. On the labels:
- `BQ`, you can ignore this
- `SPARK~1` spark computes some data
- `SPARK~2` is 1st slow period
- `SPARK~3` is 2nd slow period

We took two 10 minute JFR profiles, those are marked `P-1` and `P-2` in the graph above. So `P-1` is solely in `SPARK~2`, and `P-2` is partially in `SPARK~2` but mostly in `SPARK~3`. Here's the [`P-1`](https://gist.githubusercontent.com/ravwojdyla/e468bace2bc899f86348dee067173270/raw/98c107ebd28608da55d84d13b3aa6eaf25b3c854/p1.png) profile, and here's [`P-2`](https://gist.githubusercontent.com/ravwojdyla/e468bace2bc899f86348dee067173270/raw/98c107ebd28608da55d84d13b3aa6eaf25b3c854/p2.png) profile.

The picture is a bit more clear when we look at the locks, here's the [report](https://gist.githubusercontent.com/ravwojdyla/e468bace2bc899f86348dee067173270/raw/c0f1fb78ac9d5f90a3106b4b43a3a7b27700f66a/locks.png). We see that the threads were blocked on locks for a total of 20.5h, mostly/specifically on the global `org.apache.parquet.hadoop.MemoryManager`, which has two synchronized methods: `addWriter` and `removeWriter`. From [parquet-mr GH src](https://github.com/apache/parquet-mr/blob/9d80330ae4948787ac0bf4e4b0d990917f106440/parquet-hadoop/src/main/java/org/apache/parquet/hadoop/MemoryManager.java#L77-L98):

{code:java}
/\*\*
- Add a new writer and its memory allocation to the memory manager.
- @param writer the new created writer
- @param allocation the requested buffer size
\*/
synchronized void addWriter(InternalParquetRecordWriter writer, Long allocation) {
Long oldValue = writerList.get(writer);
if (oldValue == null) {
writerList.put(writer, allocation);
} else {
throw new IllegalArgumentException("[BUG] The Parquet Memory Manager should not add an " +
"instance of InternalParquetRecordWriter more than once. The Manager already contains " +
"the writer: " + writer);
}
updateAllocation();
}

/\*\*
- Remove the given writer from the memory manager.
- @param writer the writer that has been closed
\*/
synchronized void removeWriter(InternalParquetRecordWriter writer) {
writerList.remove(writer);
if (!writerList.isEmpty()) {
updateAllocation();
}
}
{code}

During the 10 minute profiling session all worker threads were mostly waiting on this lock.

It appears that a combination of large number of writers created via Spark's `DynamicPartitionDataSingleWriter` and the `MemoryManager` synchronization bottleneck drastically reduces the performance by starving the writer threads.

**Reporter**: [Rafal Wojdyla](https://issues.apache.org/jira/secure/ViewProfile.jspa?name=ravwojdyla)
#### Related issues:
- [DynamicPartitionDataSingleWriter is being starved by Parquet MemoryManager](https://issues.apache.org/jira/browse/SPARK-44003) (relates to)
#### PRs and other links:
- [GitHub Pull Request #1240](https://github.com/apache/parquet-mr/pull/1240)

**Note**: *This issue was originally created as [PARQUET-2412](https://issues.apache.org/jira/browse/PARQUET-2412). Please see the [migration documentation](https://issues.apache.org/jira/browse/PARQUET-2502) for further details.*

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

parquet-hadoop/src/main/java/org/apache/parquet/hadoop/MemoryManager.java から始め、特に同期された addWriter メソッドと removeWriter メソッドを確認し、JFR と lock のレポートを調査します。関連する DynamicPartitionDataSingleWriter の動作と PR #1240 を確認します。同期のボトルネックに対処しつつ、writer の登録と allocation の更新を維持できれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
java
領域
performance
issue の種類
バグ
難易度
5/5
見積もり時間
1週間以上
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
25/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。