AWS Lambda for Java performance analysis.

Loading times for infrequent calls — What to expect?

AWS lambda is a great service that Amazon introduced in 2014. It allows you to execute code without having to worry about provisioning infrastructure. Amazon takes care of making sure there is capacity to execute your function.

With AWS Lambda, you pay only for what you use.

Duration is calculated from the time your code begins executing until it returns or otherwise terminates, rounded up to the nearest 100ms. The price depends on the amount of memory you allocate to your function. You are charged $0.00001667 for every GB-second used. In addition to that, you pay 0.20$ for your first million requests.

As an example, if you have a function that takes 0.101 seconds to execute, and you assign 256MB of ram to it, executing it 1 million times, would cost you only 1.134$ (even less if you count the free tier).

That sounds absolutely great, however, there are some caveats.

It takes some time for a java-lambda to load, mainly due to classloading. If you don’t execute your lambda function very frequently, the execution time is a lot higher (up to 1000 times slower).

In a forum post, Amazon responded :

“Lambda does have higher execution times on “cold” calls (with Java having higher latency than node). …, allocating more resources to your function does help with this. We have ongoing work to improve this. However, we typically see the same or faster runtimes for Java compared to node for subsequent invocations (starting from the second time you call your Lambda function), because of the way we reuse execution containers — for more details, check out this blog.”

Because it isn’t very clear when you can expect a “cold”-call, I decided to find out. I setup a little experiment where I analyze what the runtimes of a java lambda function would be, in relation to the memory assignment and the interval between executions.

The jar that was used for this experiment was 6.276kb and contains the following libraries :

  • aws-java-sdk-dynamodb
  • aws-java-sdk-cloudwatch
  • aws-lambda-java-core
  • aws-java-sdk-sns

To really be able to focus only on the overhead, the lambda function used for testing doesn’t really do anything, it takes the following input :

{
"action": "Ping"
}

and returns the following output :

{
"message": "Pong",
"success": true
}

To determine the impact of “cold” executions, I created 4 identical lambda functions with different memory assigned to them : 128MB, 256MB, 512MB , 1024MB.

All of these functions were executed 10 times per interval at different intervals between 5 seconds and 2 hours. Between each test set, each function was executed three times to ensure the container was loaded.

The raw test results can be accessed here : https://goo.gl/RKdM8m .

From this test, there are a few interesting conclusions :

  • Infrequent calls to lambda functions can make a single invocation up to 1000 times slower.
  • Containers for functions with a low memory assignment have shorter lifetimes.
  • The longer the interval, the longer the startup time for a container is.

The first two are not unexpected, but the third conclusion came as a surprise to me. I’m really curious to what the reason for this behaviour would be. It would be great if someone at Amazon could respond to these findings, and confirm or refute these conclusions.

I think I’m not the only one that is interested in reducing the load times of java lambda’s, so any information from amazon on what to expect would be helpful.