[ 
https://issues.apache.org/jira/browse/HADOOP-20058?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Colm Dougan updated HADOOP-20058:
---------------------------------
    Description: 

Since HADOOP-19559 (3.4.3, 3.5.0), the default value of 
{{fs.s3a.input.stream.type}} changed from {{classic}} to {{analytics}}. As a 
result, each {{S3AFileSystem}} reads through an analyticsaccelerator-s3 
{{BlobStore}}. In the library version Hadoop ships (1.3.1), that store keeps an 
entry for every distinct object read until the filesystem is closed: its 
periodic cleanup frees the cached data, but not the entries.

With the filesystem cache, an S3A filesystem typically lives as long as the 
process, so a long-running service that keeps reading new objects grows its 
heap without limit. Short-lived jobs don't notice because the filesystem is 
discarded at exit.

The library issue, with a library-only reproduction, is 
[https://github.com/awslabs/analytics-accelerator-s3/issues/371], and a 
proposed fix is [https://github.com/awslabs/analytics-accelerator-s3/pull/372].

h3. Which reads are affected

Not every read leaves an entry. The library chooses how to handle each stream 
from the file name and the read policy, and streams it handles as sequential 
remove their entry when closed. So it depends on the file type and how the file 
is opened:

||Read||Entry left after close||
|{{.avro}}, plain {{FileSystem.open()}}|yes|
|{{.parquet}}, plain {{FileSystem.open()}}|yes|
|{{.json}} (also {{.csv}}, {{.txt}}), plain {{FileSystem.open()}}|no|
|{{.avro}}, {{openFile()}} with read policy {{sequential}} or {{whole-file}}|no|
|{{.avro}}, with {{fs.s3a.experimental.input.fadvise=sequential}}|no|

The attached project tests each row; {{.csv}}, {{.txt}} and {{whole-file}} are 
from the library's {{ObjectFormatSelector}} and {{AnalyticsStream}}'s 
read-policy mapping rather than tested.

So a plain {{open()}} of a non-text file builds up, which is the common case. 
For example, Apache Iceberg's {{HadoopInputFile}} uses a plain 
{{fs.open(path)}}, so every Avro manifest and manifest list read through 
HadoopFileIO on S3A leaves an entry, while its {{.metadata.json}} files don't. 
That is how we found it: a long-running Iceberg replication service ran out of 
a 160 MB heap after about 1,000 table commits.

h3. Reproduction through S3A

The attached Gradle project reproduces it through a Hadoop 3.5.0 
{{S3AFileSystem}} with default settings, using hadoop-aws's own 
{{AbstractS3AMockTest}} and {{MockS3ClientFactory}}, so no endpoint is needed 
({{./gradlew test}}, about 30 seconds, Java 17). Every stream is opened, read 
fully and closed.

||Check||Result||
|Entries after reading 2,000 distinct .avro objects (4 KB each)|2,000|
|After re-reading 1,000 of them|still 2,000 (one entry per distinct object)|
|12 seconds later, no reads|still 2,000|
|After reading 6,000 distinct objects|6,000, no limit reached|
|Heap held with the filesystem open|about 31 KB per object read|
|Heap held after {{fs.close()}}|back to the starting level|
|Same reads with {{fs.s3a.input.stream.type=classic}}|about 80 bytes per object|

With a 160 MB heap the default stream ran out of memory after 2,000 to 3,000 
distinct objects; with {{classic}} the same 50,000 reads completed.

h3. Workarounds

* {{fs.s3a.input.stream.type=classic}}
* {{fs.s3a.experimental.input.fadvise=sequential}}, at the cost of the 
analytics stream's format-specific handling

h3. Suggested changes in Hadoop

# Once a fixed analyticsaccelerator-s3 release is available, upgrade to it.
# Documentation: the default change isn't visible to users today.
#* The 3.4.3 and 3.5.0 release notes pages don't mention HADOOP-19559 or the 
stream type change; the note is only in the JIRA's release-note field.
#* {{hadoop-aws/src/site/markdown/tools/hadoop-aws/reading.md}} in 3.5.0 still 
lists {{classic}} as the default for {{fs.s3a.input.stream.type}}, while 
{{StreamIntegration.DEFAULT_STREAM_TYPE}} is {{Analytics}}.
#* Until a fixed library is shipped, it may be worth noting {{classic}} for 
long-running processes there.

ATTACHMENT:  [^s3a-analytics-blobstore-repro.zip] 


  was:

Since HADOOP-19559 (3.4.3, 3.5.0), the default value of 
{{fs.s3a.input.stream.type}} changed from {{classic}} to {{analytics}}. As a 
result, each {{S3AFileSystem}} reads through an analyticsaccelerator-s3 
{{BlobStore}}. In the library version Hadoop ships (1.3.1), that store keeps an 
entry for every distinct object read until the filesystem is closed: its 
periodic cleanup frees the cached data, but not the entries.

With the filesystem cache, an S3A filesystem typically lives as long as the 
process, so a long-running service that keeps reading new objects grows its 
heap without limit. Short-lived jobs don't notice because the filesystem is 
discarded at exit.

The library issue, with a library-only reproduction, is 
[https://github.com/awslabs/analytics-accelerator-s3/issues/371], and a 
proposed fix is [https://github.com/awslabs/analytics-accelerator-s3/pull/372].

h3. Reproduction through S3A

The attached Gradle project reproduces it through a Hadoop 3.5.0 
{{S3AFileSystem}} with default settings, using hadoop-aws's own 
{{AbstractS3AMockTest}} and {{MockS3ClientFactory}}, so no endpoint is needed 
({{./gradlew test}}, about 30 seconds, Java 17). Every stream is opened, read 
fully and closed.

||Check||Result||
|Entries after reading 2,000 distinct .avro objects (4 KB each)|2,000|
|After re-reading 1,000 of them|still 2,000 (one entry per distinct object)|
|12 seconds later, no reads|still 2,000|
|After reading 6,000 distinct objects|6,000, no limit reached|
|Heap held with the filesystem open|about 31 KB per object read|
|Heap held after {{fs.close()}}|back to the starting level|
|Same reads with {{fs.s3a.input.stream.type=classic}}|about 80 bytes per object|

With a 160 MB heap the default stream ran out of memory after 2,000 to 3,000 
distinct objects; with {{classic}} the same 50,000 reads completed.

Whether a read leaves an entry depends on how the library handles it. A plain 
{{FileSystem.open()}} of a {{.avro}} or {{.parquet}} file leaves one; {{.json}} 
files, {{openFile()}} with read policy {{sequential}}, and 
{{fs.s3a.experimental.input.fadvise=sequential}} don't. Apache Iceberg's 
{{HadoopInputFile}} uses a plain {{fs.open(path)}}, so every Avro manifest and 
manifest list read through HadoopFileIO on S3A leaves an entry. That is how we 
found it: a long-running Iceberg replication service ran out of a 160 MB heap 
after about 1,000 table commits.

h3. Workarounds

* {{fs.s3a.input.stream.type=classic}}
* {{fs.s3a.experimental.input.fadvise=sequential}}, at the cost of the 
analytics stream's format-specific handling

h3. Suggested changes in Hadoop

# Once a fixed analyticsaccelerator-s3 release is available, upgrade to it.
# Documentation: the default change isn't visible to users today.
#* The 3.4.3 and 3.5.0 release notes pages don't mention HADOOP-19559 or the 
stream type change; the note is only in the JIRA's release-note field.
#* {{hadoop-aws/src/site/markdown/tools/hadoop-aws/reading.md}} in 3.5.0 still 
lists {{classic}} as the default for {{fs.s3a.input.stream.type}}, while 
{{StreamIntegration.DEFAULT_STREAM_TYPE}} is {{Analytics}}.
#* Until a fixed library is shipped, it may be worth noting {{classic}} for 
long-running processes there.

ATTACHMENT: s3a-analytics-blobstore-repro.zip



> S3A: default analytics input stream keeps per-object state for the life of 
> the filesystem, so heap grows unbounded in long-running processes
> --------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HADOOP-20058
>                 URL: https://issues.apache.org/jira/browse/HADOOP-20058
>             Project: Hadoop Common
>          Issue Type: Bug
>          Components: fs/s3
>    Affects Versions: 3.5.0, 3.4.3
>         Environment: hadoop-aws 3.5.0 (also 3.4.3), analyticsaccelerator-s3 
> 1.3.1, default S3A settings (fs.s3a.input.stream.type unset, so analytics). 
> Java 17, Linux. Reproduced with hadoop-aws's mock S3 client (no endpoint) and 
> against S3-compatible stores (MinIO, Ceph RGW).
>            Reporter: Colm Dougan
>            Priority: Major
>         Attachments: s3a-analytics-blobstore-repro.zip
>
>
> Since HADOOP-19559 (3.4.3, 3.5.0), the default value of 
> {{fs.s3a.input.stream.type}} changed from {{classic}} to {{analytics}}. As a 
> result, each {{S3AFileSystem}} reads through an analyticsaccelerator-s3 
> {{BlobStore}}. In the library version Hadoop ships (1.3.1), that store keeps 
> an entry for every distinct object read until the filesystem is closed: its 
> periodic cleanup frees the cached data, but not the entries.
> With the filesystem cache, an S3A filesystem typically lives as long as the 
> process, so a long-running service that keeps reading new objects grows its 
> heap without limit. Short-lived jobs don't notice because the filesystem is 
> discarded at exit.
> The library issue, with a library-only reproduction, is 
> [https://github.com/awslabs/analytics-accelerator-s3/issues/371], and a 
> proposed fix is 
> [https://github.com/awslabs/analytics-accelerator-s3/pull/372].
> h3. Which reads are affected
> Not every read leaves an entry. The library chooses how to handle each stream 
> from the file name and the read policy, and streams it handles as sequential 
> remove their entry when closed. So it depends on the file type and how the 
> file is opened:
> ||Read||Entry left after close||
> |{{.avro}}, plain {{FileSystem.open()}}|yes|
> |{{.parquet}}, plain {{FileSystem.open()}}|yes|
> |{{.json}} (also {{.csv}}, {{.txt}}), plain {{FileSystem.open()}}|no|
> |{{.avro}}, {{openFile()}} with read policy {{sequential}} or 
> {{whole-file}}|no|
> |{{.avro}}, with {{fs.s3a.experimental.input.fadvise=sequential}}|no|
> The attached project tests each row; {{.csv}}, {{.txt}} and {{whole-file}} 
> are from the library's {{ObjectFormatSelector}} and {{AnalyticsStream}}'s 
> read-policy mapping rather than tested.
> So a plain {{open()}} of a non-text file builds up, which is the common case. 
> For example, Apache Iceberg's {{HadoopInputFile}} uses a plain 
> {{fs.open(path)}}, so every Avro manifest and manifest list read through 
> HadoopFileIO on S3A leaves an entry, while its {{.metadata.json}} files 
> don't. That is how we found it: a long-running Iceberg replication service 
> ran out of a 160 MB heap after about 1,000 table commits.
> h3. Reproduction through S3A
> The attached Gradle project reproduces it through a Hadoop 3.5.0 
> {{S3AFileSystem}} with default settings, using hadoop-aws's own 
> {{AbstractS3AMockTest}} and {{MockS3ClientFactory}}, so no endpoint is needed 
> ({{./gradlew test}}, about 30 seconds, Java 17). Every stream is opened, read 
> fully and closed.
> ||Check||Result||
> |Entries after reading 2,000 distinct .avro objects (4 KB each)|2,000|
> |After re-reading 1,000 of them|still 2,000 (one entry per distinct object)|
> |12 seconds later, no reads|still 2,000|
> |After reading 6,000 distinct objects|6,000, no limit reached|
> |Heap held with the filesystem open|about 31 KB per object read|
> |Heap held after {{fs.close()}}|back to the starting level|
> |Same reads with {{fs.s3a.input.stream.type=classic}}|about 80 bytes per 
> object|
> With a 160 MB heap the default stream ran out of memory after 2,000 to 3,000 
> distinct objects; with {{classic}} the same 50,000 reads completed.
> h3. Workarounds
> * {{fs.s3a.input.stream.type=classic}}
> * {{fs.s3a.experimental.input.fadvise=sequential}}, at the cost of the 
> analytics stream's format-specific handling
> h3. Suggested changes in Hadoop
> # Once a fixed analyticsaccelerator-s3 release is available, upgrade to it.
> # Documentation: the default change isn't visible to users today.
> #* The 3.4.3 and 3.5.0 release notes pages don't mention HADOOP-19559 or the 
> stream type change; the note is only in the JIRA's release-note field.
> #* {{hadoop-aws/src/site/markdown/tools/hadoop-aws/reading.md}} in 3.5.0 
> still lists {{classic}} as the default for {{fs.s3a.input.stream.type}}, 
> while {{StreamIntegration.DEFAULT_STREAM_TYPE}} is {{Analytics}}.
> #* Until a fixed library is shipped, it may be worth noting {{classic}} for 
> long-running processes there.
> ATTACHMENT:  [^s3a-analytics-blobstore-repro.zip] 



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to