Skip to content

Increase memory to avoid OOM errors during download#8

Merged
simone-smith merged 1 commit into
mainfrom
increase-memory-to-avoid-oom-errors
Nov 10, 2021
Merged

Increase memory to avoid OOM errors during download#8
simone-smith merged 1 commit into
mainfrom
increase-memory-to-avoid-oom-errors

Conversation

@simone-smith

@simone-smith simone-smith commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

The GeoIp file has grown slightly larger (from 134368384 to 134801401 bytes) - and now we're seeing consistent OutOfMemoryErrors?!

Memory usage as reported at the end of an unsuccessful run with 512MB:

REPORT RequestId: 8f4b33f4-8913-4095-9bfa-3b1f64fd1e6a Duration: 38466.58 ms Billed Duration: 38467 ms Memory Size: 512 MB Max Memory Used: 395 MB

We increased memory size to 1024MB, and the function ran successfully:

REPORT RequestId: b4a76e3b-581d-4296-a613-0ca50ec92e2f Duration: 19931.72 ms Billed Duration: 19932 ms Memory Size: 1024 MB Max Memory Used: 750 MB Init Duration: 416.56 ms

...this would indicate, for the time being at least, we need a minimum of 750 MB for this lambda. It's surprisingly inefficent given the streaming code involved though 😢

Java heap space: java.lang.OutOfMemoryError
java.lang.OutOfMemoryError: Java heap space
	at java.base/java.util.Arrays.copyOf(Unknown Source)
	at java.base/java.io.ByteArrayOutputStream.grow(Unknown Source)
	at java.base/java.io.ByteArrayOutputStream.ensureCapacity(Unknown Source)
	at java.base/java.io.ByteArrayOutputStream.write(Unknown Source)
	at java.base/sun.net.www.http.PosterOutputStream.write(Unknown Source)
	at software.amazon.awssdk.utils.IoUtils.copy(IoUtils.java:113)
	at software.amazon.awssdk.utils.IoUtils.copy(IoUtils.java:99)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.lambda$null$0(UrlConnectionHttpClient.java:208)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable$$Lambda$437/0x000000084036d840.get(Unknown Source)
	at software.amazon.awssdk.utils.FunctionalUtils.lambda$safeSupplier$4(FunctionalUtils.java:108)
	at software.amazon.awssdk.utils.FunctionalUtils$$Lambda$77/0x000000084016e840.get(Unknown Source)
	at software.amazon.awssdk.utils.FunctionalUtils.invokeSafely(FunctionalUtils.java:136)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.lambda$call$1(UrlConnectionHttpClient.java:208)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable$$Lambda$436/0x000000084036e440.accept(Unknown Source)
	at java.base/java.util.Optional.ifPresent(Unknown Source)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.call(UrlConnectionHttpClient.java:207)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.call(UrlConnectionHttpClient.java:193)
	at software.amazon.awssdk.core.internal.util.MetricUtils.measureDurationUnsafe(MetricUtils.java:64)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.executeHttpRequest(MakeHttpRequestStage.java:76)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.execute(MakeHttpRequestStage.java:55)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.execute(MakeHttpRequestStage.java:39)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:73)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:42)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:78)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:40)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptMetricCollectionStage.execute(ApiCallAttemptMetricCollectionStage.java:50)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptMetricCollectionStage.execute(ApiCallAttemptMetricCollectionStage.java:36)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:64)

This was causing builds to fail, but increasing the memory in the Lambda console has fixed the issue:

image

The Cloudformation stack has been updated to reflect this new value too:

image

Closes #7

The GeoIp file has grown _slightly_ larger (from 134368384 to 134801401 bytes) - and now we're seeing consistent OutOfMemoryErrors?!

Memory usage as reported at the end of an unsuccessful run with 512MB:

> REPORT RequestId: 8f4b33f4-8913-4095-9bfa-3b1f64fd1e6a	Duration: 38466.58 ms	Billed Duration: 38467 ms	Memory Size: 512 MB	Max Memory Used: 395 MB

We increased memory size to 1024MB, and the function ran successfully:

> REPORT RequestId: b4a76e3b-581d-4296-a613-0ca50ec92e2f	Duration: 19931.72 ms	Billed Duration: 19932 ms	Memory Size: 1024 MB	Max Memory Used: 750 MB	Init Duration: 416.56 ms

...this would indicate, for the time being at least, we need a minimum of 750 MB for this lambda. It's surprisingly inefficent given the streaming code involved though 😢

```
Java heap space: java.lang.OutOfMemoryError
java.lang.OutOfMemoryError: Java heap space
	at java.base/java.util.Arrays.copyOf(Unknown Source)
	at java.base/java.io.ByteArrayOutputStream.grow(Unknown Source)
	at java.base/java.io.ByteArrayOutputStream.ensureCapacity(Unknown Source)
	at java.base/java.io.ByteArrayOutputStream.write(Unknown Source)
	at java.base/sun.net.www.http.PosterOutputStream.write(Unknown Source)
	at software.amazon.awssdk.utils.IoUtils.copy(IoUtils.java:113)
	at software.amazon.awssdk.utils.IoUtils.copy(IoUtils.java:99)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.lambda$null$0(UrlConnectionHttpClient.java:208)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable$$Lambda$437/0x000000084036d840.get(Unknown Source)
	at software.amazon.awssdk.utils.FunctionalUtils.lambda$safeSupplier$4(FunctionalUtils.java:108)
	at software.amazon.awssdk.utils.FunctionalUtils$$Lambda$77/0x000000084016e840.get(Unknown Source)
	at software.amazon.awssdk.utils.FunctionalUtils.invokeSafely(FunctionalUtils.java:136)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.lambda$call$1(UrlConnectionHttpClient.java:208)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable$$Lambda$436/0x000000084036e440.accept(Unknown Source)
	at java.base/java.util.Optional.ifPresent(Unknown Source)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.call(UrlConnectionHttpClient.java:207)
	at software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient$RequestCallable.call(UrlConnectionHttpClient.java:193)
	at software.amazon.awssdk.core.internal.util.MetricUtils.measureDurationUnsafe(MetricUtils.java:64)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.executeHttpRequest(MakeHttpRequestStage.java:76)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.execute(MakeHttpRequestStage.java:55)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.execute(MakeHttpRequestStage.java:39)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:73)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:42)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:78)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:40)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptMetricCollectionStage.execute(ApiCallAttemptMetricCollectionStage.java:50)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptMetricCollectionStage.execute(ApiCallAttemptMetricCollectionStage.java:36)
	at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:64)
```

Relates to #7

Co-authored-by: Roberto Tyley <roberto.tyley@guardian.co.uk>
@simone-smith simone-smith merged commit 810bd71 into main Nov 10, 2021
rtyley added a commit that referenced this pull request Dec 8, 2021
AWS SDK v2.17.97 includes aws/aws-sdk-java-v2#2848,
which lowers memory consumption by streaming request data, rather than
loading the entire request into memory before sending it, which can make
a large difference to consumption of memory when uploading large files
to S3.

In the case of the `geoip-db-refresher`, it's actually economical to
run with _more_ RAM than we need (we're billed for fewer GB-seconds
when specifying a `MemorySize` of 1536MB than 1024MB, as AWS Lambdas
are given more CPU to match increased memory) so this is no longer a
serious issue for the 134MB file uploaded here!

See also:

* #7
* #8
* 1de50ef
* https://aws.amazon.com/lambda/pricing/
* https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-common.html#configuration-memory-console
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OutOfMemoryError

2 participants