-
Notifications
You must be signed in to change notification settings - Fork 853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
First DynamoDB request is very slow #1340
Comments
Hi @stuartleylandcole The initial request being slow is because the HTTP client must open a new socket and perform an SSL handshake which are slow and costly operations. |
For your first question, it looks like you already use the |
You can also have a look at this comment #6 (comment) but it looks like you more or less follow the guidelines already. |
Hi @dagnir, thank you for your replies! I've been doing some further investigation and wanted to report back my findings and ask for some further assistance. With a 1024MB Lambda the first DynamoDB request reliably takes 2s from executing the request to receiving a response. Note that this does not include time to build
I have also run the same code on a 2048MB Lambda to compare times and they are roughly half the time for the 1024MB Lambda, except for building
A quick summary (all times in ms):
Even with the timings on the 2048MB sized Lambda this makes it quite difficult to run a REST API using Lambdas as a cold start will incur both the normal Lambda cold start time (1-2s) plus the DynamoDB overhead (1s). Equally these Lambdas do not require anything like 2GB of memory, they are using less than 200MB but I realise that CPU scales with memory which is why I performed this test - ideally I would be using 512MB or less. Some questions to finish with:
Thank you for any help you can provide. Hopefully we are able to reduce these times as at the moment I'm not sure that Lambdas providing a REST API in front of DynamoDB is a viable architecture. |
Hi @stuartleylandcole, the constant of ~400ms for instantiating The 'Unknown' step in the logs appears the the credentials loading mechanism. This is in line with what's happening since this is happening after a call to DDB is made, wherer the SDK must then resolve the credentials to use for signing. You can reduce this by providing a specific credentials provider, rather that |
Hi @stuartleylandcole, has @dagnir answered your questions? Do you have any other question? |
Hi @debora-ito @dagnir. Thank you for your reply and apologies for not responding sooner. I think my question has been answered, at least in relation to the SDK - I have others concerns about the viability of Lambdas for a REST API backed by DynamoDB given the timings shown above but I don't think this is the place to raise them. Do you happen to know the correct place to raise this? Many thanks for your help! I'm happy for this issue to be closed now. |
I would suggest reaching out to the AWS Support or directly to service team via AWS Forums. |
hi @stuartleylandcole , thank you so much for a very detailed explanation and benchmark. I am actually having the same issue, and your investigation results above is really helpful. I would like to know if you have found some other way to shave off some more time in regards to the first request to DynamoDb. Have you gained any updates from Support or other forums? I think it is unacceptable that a 1024MB lambda takes 2s to execute first DynamoDb request. This is actually worse than AWS Lambda cold start itself :( |
Hi @ocind. I'm quite surprised more people haven't encountered the problem, it fundamentally undermines one of the main reference architectures for AWS Lambda IMO. The only way we have found to reduce the time is by warming the Lambdas. However the normal Lambda warming (for example, using, serverless-plugin-warmup) isn't enough; you need to make a Dynamo request so that the connection is established to do the SSL negotiation, setup connection pooling, etc. We use |
hi @stuartleylandcole I think my use case is very similar to yours. We also use Dynamo and Cognito. On lambda warmup calls, currently we also initialize all the sdk clients and try to make a dummy request for each one. In one of our Lambda functions, we actually have 2 Dynamo tables to read values from. I did some experiment couple months ago, and we found that while writing to different tables, first request to each table would involve setting up SSL handshake again. Currently we warm the connections by performing
Hmmm, I didn't know that Thank you for the insights |
We have the same issue. Containers: Logs say that the lambda uses not more 200 Mb of RAM. I suppose the DynamoDB client (from AWS SDK) is not efficient and should be improved with refactoring. |
I am seeing a similar situation with S3 clients inside a Lambda. The first creation of a client and first request are significantly slower than following requests (about 10 seconds vs. 200 ms) with 512M Lambda. |
Just an assumption: |
I also have encountered this issue - I tried a few things but found that increasing the memory size was the only thing that seemed to make an impact. My findings:
We are using the |
Hi all, we have released a maven archetype
Please try it out and let us know if you have any feedback! :) |
@zoewangg many thanks for this! Could you highlight the key parts of the archetype in relation to this issue (i.e. Initialisation of the dynamo client)? I've taken a look at the code and the most obvious part is initialising the client in the Lambda handler constructor - are there other aspects to it? Thanks again! |
@stuartleylandcole Sure! Below are the patterns we use in the archetype to reduce SDK startup time:
Lines 37 to 46 in c72d2b5
Update: please check out https://aws.amazon.com/blogs/developer/tuning-the-aws-java-sdk-2-x-to-reduce-startup-time/ for best practices to reduce SDK startup time |
@ocind @stuartleylandcole . I'm thinking about the following setup to eliminate the problem:
I'm sure this eliminates the overhead just after the environment has been provisioned, cause I've seen that. What do you think? |
@Nxtra Yeah, you can consider pre-warmuping the client by making a simple GET api after you create the client to establish a connection in advance. By default, the SDK closes idle connections after 60 seconds. You can increase it, but keep in mind that idle connections can also be closed on the service side after certain amount of time, which cannot be configured on the SDK side. Line 118 in c72d2b5
I'm not super familiar with provisioned concurrency feature of Lambda function, and I'd recommend reaching out to Lambda team on AWS forums if you have any questions regarding it. |
For me, it looks like there is no any problems with dynamodb connections
and the time to establish it (honestly I did not measure it).
I think the issue is in something different, because the first request time
is very very varies on the Lambda Memory settings and as consequeuence the
CPU quota Lambda has.
If you have a big Lambda instance like 3 Gb, there is no any serious delay
for the first request. Right ? Actually, any HTTP connection (which
DynamoDB uses) must not require too much CPU resources, in case if you do
not launch a super duper connection pool for the client.
Yes, using provisioned concurrency feature may be a kind of workaround, but
it is not a solution, you can not keep many provisioned lambda instances
because it costs money (I think using the 3 Gb Lambda will be more
cheaper) .
Also, in case of spike of requests you will get the issue again, when you
need more lambda instances than you have provisioned.
I still think that there is an issue in DynamoDB client library for java,
maybe it is not optimized properly or has a problem with a dependency libs
which DynamoDB client uses.
…On Tue, Mar 31, 2020 at 1:44 AM Zoe Wang ***@***.***> wrote:
@Nxtra <https://github.com/Nxtra> Yeah, you can consider pre-warmuping
the client by making a simple GET api after you create the client to
establish a connection in advance. By default, the SDK closes idle
connections after 60 seconds. You can increase it, but keep in mind that
idle connections can also be closed on the service side after certain
amount of time, which cannot be configured on the SDK side.
https://github.com/aws/aws-sdk-java-v2/blob/c72d2b554de92258b9cfced4f8f54f3ba714cf92/http-client-spi/src/main/java/software/amazon/awssdk/http/SdkHttpConfigurationOption.java#L118
I'm not super familiar with provisioned concurrency feature of Lambda
function, and I'd recommend reaching out to Lambda team on AWS forums if
you have any questions regarding it.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#1340 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGYOKFGIGJEOD4Z67PYEX5LRKEODTANCNFSM4IBIJFLA>
.
--
Best regards,
Sergei Biletnikov
|
Hi @biletnikov, from your previous comment, it seems you are using DynamoDBMapper from AWS Java SDK 1.11.x. We are aware of the slow startup issue in 1.11.x, and unfortunately there is not much we can do to improve it while still maintaining backwards compatibility. We are actively working on the implementation of Dynamodb mapper 2.x, and it's currently in preview. https://github.com/aws/aws-sdk-java-v2/tree/master/services-custom/dynamodb-enhanced |
Hi Zoe,
right, I am using DynamoDBMapper from AWS Java SDK 1.11.x
Ok, good that you confirm the startup issue in this lib.
Looking forward for Dynamodb mapper 2.x release, so we could use it for
production projects.
Could you roughly estimate when it will be ready? in 1 month, 3 months, 6
months ?
Thanks.
…On Tue, Mar 31, 2020 at 8:37 PM Zoe Wang ***@***.***> wrote:
Hi @biletnikov <https://github.com/biletnikov>, from your previous
comment, it seems you are using DynamoDBMapper from AWS Java SDK 1.11.x. We
are aware of the slow startup issue in 1.11.x, and unfortunately there is
not much we can do to improve it while still maintaining backwards
compatibility.
We are actively working on the implementation of Dynamodb mapper 2.x, and
it's currently in preview.
https://github.com/aws/aws-sdk-java-v2/tree/master/services-custom/dynamodb-enhanced
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1340 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGYOKFBROXRYBBHOLBQLP5TRKIS37ANCNFSM4IBIJFLA>
.
--
Best regards,
Sergei Biletnikov
|
Great to hear that! |
Hi @biletnikov, we don't have a public timeline at the moment, but DynamoDbMapper v2 is definitely one of our top priorities right now. The work is tracked in #35 Hi @Nxtra Sure! One of the main reasons is that 1.11.x SDK uses ApacheHttpClient under the hood and initializing it can be expensive. Checkout this comment aws/aws-sdk-java#1774 (comment) for more info. Let me know if you have further questions! |
@zoewangg Hi, we've used enhanced since June 2020, and current using version is one of Mar, 2021, we noticed that slow start up is still existing and hard to optimized event if I did a pre dummy request for one of our |
Hi @talentprince thank you for your feedback. Are you using static table schema? Can you share how you create the DynamodbEnhancedClient? What is your memory setting? On a side note, if startup latency is critical to your application, you might consider GraalVM native image, which has faster startup time compared with JVM. https://aws.amazon.com/blogs/developer/graalvm-native-image-support-in-the-aws-sdk-for-java-2-x/ |
Hi, @zoewangg , we are not using lambda but springboot+eks, memory is 600M, DynamodbEnhancedClient is a spring bean, and table schema is initialized as fields of our storage client (another bean). |
Hi @zoewangg, i am getting reestablishment of connection after every one min of idle time. I am using ApacheHttpClient for db connection. with all default value from SdkHttpConfigurationOption, i observed in log that the connection is getting shut down after every one min of idle time. so, i increased CONNECTION_MAX_IDLE_TIMEOUT to 10 min. But now the connection is not getting shut down by itself after one min of idle time but when another request is fired after 2-3 min of idle time. it is sending the request first then shutting the connection then reestablishing the connection, which infact take more latency then first default case. i tried with tcpKeepAlive setting to true but still same result. i also increased connection ttl to 10 min but still no change. BTW i am not using lambda, it is ECS to dynamodb |
@Nandlalaji i think your problem is Connection Keep Alive, it's by default active for new release of SDK as i know but if you use the V1 or V2 you need to flag it as true when creating the http client |
Thanks for replying @sl-omideidivandi. i have set tcpKeepAlive as true. But still same behaviour. i mean after 2-3 idle time if request is made, first the connection is shutting down then reestablishing the connection. Now i noticed some different issue. To avoid this above issue i am warming up the DB by making dummy DB call every 1 min. But this solution seems not full proof. i mean now the 20% has decrease to 1% but still this issue exist I tried to investigate more by printing SDK log. and found logs similar to @stuartleylandcole. only that after DynamoDBEnhancedClient call it is going to ExecutionInterceptorChain -Creating an interceptor chain that will apply interceptors. should i be creating a bug for this. BTW i am doing all this from ECS. Lambda is not involve in my case. |
In 2019 Re:Invent, Stefano Buliani gave a speech regarding how to optimize Lambda execution time. Here's the presentation video: https://youtu.be/ddg1u5HLwg8?si=gKOO1Fnqj0ggV2mN&t=1515. He mentioned the following points regarding AWS SDK for Java v2:
And the solution is
I believe TLS handshake, socket setup definitely contributed to the long latency. But I think the lazy loading probably contributed more to the latency. Hope this helps. |
Expected Behavior
All DynamoDB queries should take in the low 10s of milliseconds.
Current Behavior
DynamoDB queries are generally in the 10s of milliseconds however the first time a Dynamo function is executed I am seeing response times around 2s, subsequent queries then fall back to the expected levels.
Possible Solution
Unsure, I haven't been able to identify anything from stepping through the code
Steps to Reproduce (for bugs)
I have written the following code to replicate the creation of the
DynamoDbClient
and the execution of four put requests. It assumes you have a table named "item" in your AWS account.The results are below.
The following is the code for the
SimpleTimer
:Results:
As you can see the first put takes 884ms then the three subsequent ones take 29, 70, and 29ms making the first request at least an order of magnitude slower. Add in the 600ms for the
DynamoDbClient
creation and that's quite a long time.Context
This code is used in a Lambda function serving a REST API which is one of the canonical use cases for Lambdas. The expectation is that the function should be quick to respond and as shown by the subsequent requests, this is a reasonable expectation. The results above are actually far better than we are seeing when deployed to Lambda - our first Dynamo execution is consistently around 2s +/-0.2s. We are not using a VPC and the Lambdas have 1024MB memory.
Your Environment
The above code was run on my machine to get the provided results but we are deploying virtually identical code to an AWS Lambda with 1024MB memory.
I have some questions:
The text was updated successfully, but these errors were encountered: