What is the right serverless solution for you?
With serverless architectures being all the rage these days, you're probably wondering what options exist for your application in this brave new world.
If you develop primarily in the AWS ecosystem, you're likely already aware of Lambda functions and how tools such as API Gateway allow us to instrument fully-functional microservices while maintaining absurdly low operational costs (or absurdly high, if your service is popular!) What you might be less familiar with, but are perhaps curious about (you did open this blog post, after all), is AWS's Fargate solution.
This post attempts to describe with some detail the two aforementioned architectural solutions with a focus on what distinguishes the two from one another, and ultimately help drive your decision to the right tool for the job at hand.
Lambda
As mentioned previously, AWS Lambda functions have (right or wrong) become almost synonymous with "serverless" in the minds of most developers. But if we consult the excellent (albeit curiously branded) serverless.com, we see a definition of "serverless" where the term "lambda" is conspicuously absent:
Just like wireless internet has wires somewhere, serverless architectures still have servers somewhere. What ‘serverless’ really means is that, as a developer you don’t have to think about those servers. You just focus on code.
After all, Serverless as a philosophy isn't limited to AWS (think Microsoft's Azure Functions as a Lambda equivalent), and so why should any single tool be representative of the philosophy?
That said, this common misconception isn't entirely without merit. Serverless functions provide an easy-to-understand implementation of a serverless microservice that many of the world's most profitable companies leverage in production today.
Just as not all tissues are "Kleenex", so too are not all serverless functions "lambdas" - the key to understanding each is to focus on the platonic form, rather than the brand. Lambdas are simply "functions" that execute in an environment where you as a developer don't have to concern yourself with the underlying server. That's it.
Because Lambdas are boiled down to the lowest functional unit of an application (a function), much of the traditional concerns an application developer needs to take into account are managed for you: runtime, OS, memory, etc. are largely defined by AWS and you're free to implement your function on top of it.
This simplistic abstraction is what really sets Lambda apart from other, more holistic approaches such as...
Fargate
Like Lambdas, Fargate (either via ECS or Kubernetes) allow us as developers to remove from scope concerns related to the physical "server" itself: things such as system memory, CPU usage, etc. Again, these things are still in use, but they are entirely managed by Jeff Bezos' team of highly skilled systems specialists. We get to focus on our code!
A keen eye, however, will notice some glaring differences between the two lists of non-concerns layed out in the above few paragraphs:
Whereas Lambdas remove concerns related to OS and runtime as well as "baremetal" concerns like CPU and memory, Fargate only handles the latter. In this way, Fargate is still technically serverless (and allows us to harvest the fiscal benefits of not running a server constantly), but still enables us to define the minutea of our code's runtime environment through the use of Containers.
Let's say, for example, that you're building an application using Node.js. If you want to run this application via a series of Lambdas, you're locked in to the two Node runtimes that AWS provides for Lambdas: Node@8
and Node@10
. Want to run Node@12
? Not an option. Need to run something as old as Node@6
? Not an option (anymore). Fargate allows you to specify exactly what your runtime environment looks like by using whatever Docker container you provide, and therein lies the key difference.
Cold Starts
So we know the key differences between these two tools, but I'd like to focus for a moment on one of their key similarities.
As mentioned before, both are technically serverless in that they satisfy the definition quoted earlier. Both run on-demand, and as such will shut down after a predetermined amount of idle use, saving you (and/or your company) precious capital.
Whenever a serverless "application" or "function" shuts down, however, it is not longer as immediately accessible as it was when it was alive and running. This is what saves you money, but with the caveat that it makes triggers to your serverless application during the "down" state measurably slower, as the responses to those triggers are blocked by the time it takes to start up the environment in which the process runs. This is a common problem in serverless architectures, and there are several ways to address this problem.
The key to managing cold-starts is to understand usage patterns of the service you're trying to build. If its going to be high-usage, then you'll likely not have to worry much about cold-starts because there will likely be long periods of "warm" servers servicing your requests - that said, if you're relying on frequent traffic to keep your serverless servers warm, you're likely toeing the line where it might make sense to pay for a constantly running compute instance (server, as opposed to serverless) for your architecture. This is an important decision that only you can make, and is outside the scope of this post.
When to use Fargate over Lambda
Assuming you've made an informed decision to go serverless, you're likely still unsure whether or not to go the "serverless functional" (lambda) route, or the "serverless container" (Fargate) route. You'll likely want to pick Fargate if:
- You need strict control over the runtime environment (Lambda only supports so much)
- Your application relies on a composition of multiple system level processes (such as daemons)
A general rule of thumb is that you need Fargate if your application needs to be run as a container (or relies heavily on processes outside of your codebase).
When to use Lambda over Fargate
Given that last statement, if the scope of your application is isolated to running the business logic you've defined in your codebase, you're likely just fine with Lambdas. You'll likely want to pick Lambdas if:
- You simply want to execute business logic, and don't rely on other processes running on the system
- The runtimes provided by AWS are sufficient to do so
In Conclusion
To be fair, this post really only captures the basics of Lambdas vs Fargate, and the considerations I've personally taken into account when architecting solutions using either one. If you'd like to learn more about Fargate, I can't recommend enough the following video by Abby Fuller from AWS.