SummaryWhen deploying serverless applications to AWS Lambda, do you create a single, monolithic function to handle all the application endpoints or a lambda function per endpoint? In this post, I will explore these two approaches to deploying serverless applications.
Function as a Service (FaaS) products allow application developers to spend less time on things like uptime and scalability and enables them to focus on the what’s important to them. The application architecture. But how do we architect these applications? Where do we start? Their are two general strategies you can pursue when building an application to run on AWS Lambda and similar FaaS offerings. You can create a single function that handles all requests to the application, or you can deploy a separate function for each endpoint of the application.
Endpoint functions are were I started when considering my first serverless application. This seems to be the model that the Serverless Framework pushes you towards. However, when building the application I found it to be problematic.
Using this model, application dependencies will need to be bundled and pushed for each function. Alternatively, AWS Lambda offers layers which can be used. However, this is additional work that needs to be done. It’s easy enough to bundle it up but you will need to want to do some automation around this as application dependencies change.
Cloud Provider Flexibility
In addition to the dependencies issue, it is likely that the providers FaaS idioms will bleed onto your architecture more when doing endpoint focused functions. This will make it more difficult should you choose to migrate your application to a different cloud provider in the future.
Possible Latency Issues
Another issue, which is more application dependent is the warmup time of each of the functions. Unused functions are killed after a timeout period. This means the next time it is called, the code has to be retrieved and started up again. With endpoints, it is more likely you will encounter warmup latency since endpoints are hit less frequently than a single function would be.
The bright side
On the plus side, monitoring and debugging should be easier as you can get an immediate idea of which endpoint is causing issues. Also, you suffer less chance of impacting other endpoints during deployments since you are not even touching them. Imagine that, we can now redeploy specific endpoints, specific HTTP methods even!
Monolithic functions. Nobody likes that word, monolithic. Isn’t that what we are trying to get away from?
With monolithic functions, like traditional applications, you add a router at the boundary that sends the message to the appropriate methods in the application. There are many libraries out there that will do this for you.
Possible Deployment Impact
There are some issues, essentially the opposite of above. You are no longer deploying individual endpoints and you will have to dig through logs to find the endpoint, or perhaps introduce an application performance management tool.
You will be able to take advantage of the increased likelihood of finding a warm function to serve requests and it makes your deployment code much thinner. No giant Serverless or CloudFormation scripts!
I am a pragmatist first, so if I were creating an application today, I would start with monolithic. I keep the lambda boundary small and isolate the “AWSisms” that impact your application architecture. This will make it easy should you choose to move to another cloud provider in the future. Perhaps you want to deploy to multiple cloud providers for resiliency.
As always, make sure the code is structured so that you can pivot to endpoint functions with minimal impact to the architecture in the future. Keep this in mind and it should help guide your architectural decisions.