1

I have two pieces of code

Lambda A : (written in Python) Lambda B : (written in NodeJs)

Scenario 1: Lambda A calls Lambda B with some payload and waits for output from lambda B. Lambda B as part of its logic makes api calls and returns data. I call the other lambda using boto3 (InvocationType: RequestResponse).

Scenario 2: I create a zip file containing both the pieces of the code and create a lambda using the zip file. In the python code, I invoke the NodeJs code using subprocess.call().

Can anyone tell me which approach is faster. what are the pros and cons of above approaches (w.r.t : billingTime, duration time, scalability etc..)

As per my understanding the cons for the above approaches will be :

Scenario 1:

  1. Because of the network call, I will be billed twice (for the network call duration)
  2. has some network overhead.

Scenario 2:

  1. Sub process creation overhead.
iwekesi
  • 2,228
  • 4
  • 19
  • 29
  • Have you tried the second scenario? Intuitively, it seems like it has the *potential* to be notably faster and cheaper, but if done sub-optimally, it could be worse. Conversely, the implications of container reuse could mean scenario 1 is more efficient unless you manage the child process in scenario 2 in a reusable way. – Michael - sqlbot Aug 22 '17 at 11:28

1 Answers1

1

The answer here boils down to "benchmark it."

The process creation overhead, itself, should be minimal, but the overhead of starting up the Node child could be a performance killer.

The reason centers around container reuse.

When a Node Lambda function is invoked for the first time, then finishes, the container and the process inside it remain on a warm standby for the next invocation. When that happens, your process is already running, and the handler function is invoked in a matter of microseconds. There is no time required to set up the container and start the process and run through any initialization code on that second invocation.

This means that, in scenario 1, the time for the function to get started is minimized. The overhead is how long it takes for the caller to make the request to Lambda and for Lambda to return the response, once available. In between those two things, there is very little time.

By contrast, if you spin up a child process with each request in scenario 2, you have all of that initialization overhead with each request.

I recently had occasion to run some code in Lambda that was in a language Lambda doesn't support, called by a Lambda function written in Node.js I do this with a child process, but with a twist: the child process was written to read from STDIN and write to STDOUT, for IPC from and to the JS code. I can then send a "request" to the child process and an event is triggered when the child writes the response.

So, the child is started from Node, with its controlling Node object in a global variable, only if not already present... but it is likely to be already present, again, due to container reuse.

In Node/Lambda, setting context.callbackWaitsForEmptyEventLoop allows the Lambda callback to consider the invocation finished, even if the event loop is still running, and this means I can leave that child process running across invocations.

With this mechanism in place, I achieve best-case runtimes for each Lambda invocation of under 3 milliseconds when the container is reused. For each new container, then first initiation of that child process is in excess of 1000 ms. The 3ms time is doubtless better than I could achieve if calling a second Lambda function from inside the first one, but the savings come fron keeping the inner process alive while the container remains alive.

Since your outer function is Python, it's not clear to me just exacrly what implications there are for you, or how useful this might be, but I thought it might serve to illustrate the value of the concept of keeping your child process alive between invocations.

But start with what you have, and benchmark both of your scenarios, multiple tines, to ensure that any longer than expected runtines aren't an artifact of new container creation.

Michael - sqlbot
  • 169,571
  • 25
  • 353
  • 427
  • Thanks for the detailed explanation Michael. My understanding about aws lambda is somewhat blurred. Can you help me understand how aws lambda handles multiple requests. Will it spawn multiple instances of the same code? If i receive 1000 requests at a given time.. will it create 1000 instances of the lambdas? Will it help to optimize the code for "warm standby" scenario if aws keeps on creating new instances for lambda execution? – iwekesi Aug 26 '17 at 07:26
  • As I mentioned [here](https://stackoverflow.com/a/45782990/1695906), enough containers are created to handle your workload of concurrent requests. Multiple requests at the same time will each get their own container, because a new container is created only when a new request arrives and there are no idle containers available to service it. Multiple requests will never hit the same container at the same time. – Michael - sqlbot Aug 27 '17 at 13:22