The activities of web applications are uncertain, sometimes they serve a huge number of workloads, but sometimes they idle without a large number of requests. The hosting of applications on virtual machines in the cloud forces us to pay for idle times too. To solve such a problem we must look at load balancing, DNS lookup, and automatic scaling. It is difficult to manage all of this and on pet projects it makes zero sense.
Serverless technologies are several years old and its popularity is increasing every year. For highly loaded systems it is a simple way of infinite scaling, and for simple pet projects it is a great opportunity for free hosting. This is what this longread is all about.
It is a way to deploy the code without deploying the server. We take our predefined function on Python (yes, we will talk only about Python here), we send it to the cloud and it works there in the sandbox that the cloud itself provides us. How this function runs, how containers can be reused, etc., depends on the vendor and can be changed.
Even though this method is called serverless, it is not really a lack of a server, we just don’t have a centralized server. But instead a bunch of decentralized services published in the cloud and are deployed automatically when the desired event occurs.
Some people compare serverless to a microservice architecture, but these are slightly different concepts, although they are close in nature. Typically, a microservice is larger in terms of both functionality and resources — ideally, each microservice should have its own database, central messaging system, and everything it needs to operate independently. A function is a relatively small piece of code that performs only one action in response to an event. Depending on how the developers have divided the application, a microservice may be equivalent to a function (i.e. perform only one action) or may consist of several functions.
We don’t write any Flask code, any Django code, nothing like that. Runtime is provided by the cloud platform and it makes decisions for us, the platform can reuse previous environments to speed up the response, load balancing, etc.
We do not pay for server rent, but for the time when our code is executed, for the milliseconds for which our request is processed. Like pay-as-you-go. This means that the payment for usage is made depending on the time of execution of a particular function. Instead of running the server 24/7, you can place lambda functions, and the server will only run during the life cycle of the request. This is great for prototyping, as you pay for the number of specific requests, and if you use AWS Lambda, you have 1 million absolutely free(!) requests per month.
We don’t store the state in functions, we can’t use global variables, we can’t store anything on the hard disk (technically it’s possible, but it doesn’t make sense and goes against the concept itself), we can only use external things — external database, external cache, external storage, etc. Thanks to this, there are no problems with horizontal scaling when there are a load and number of requests. And all this allows us to stop paying attention to the infrastructure and engage in real code writing and business logic of the application.
Our code is secondary to the infrastructure. Any application is essentially a way to take user data, do something with it, and place it somewhere in one form or another. And in the case of a serverless infrastructure, we take that infrastructure that cloud service providers offer us and connect those services that already have some kind of logic. We write a function that takes what came to the web server and places it somewhere in the database, and we build a lot of these little bridges. Our application now is a grid of small functions. This way, the code is not the backbone of the application but is a glue that binds the various infrastructure components. When building such applications, development usually starts with the infrastructure.
There are disadvantages, of course.
Obviously, here we become even more dependent on vendors who provide us with their infrastructure. The so-called vendor lock. Functions designed for AWS will be very difficult to transfer, for example, to Google Cloud. And not because of the features themselves, Python is Python even in Google, but rather because you rarely use serverless features in isolation. Besides them, you will use a database, messaging queues, logging systems, etc., which are completely different from one manufacturer to another. However, even this functionality can be made independent from the cloud provider if you wish.
It is evident that using a third-party service can let you lead to lesser system control. It is because you will be unable to understand the whole system properly. Basically it leads to limitations on what you’re able to use in your application.
Another disadvantage is that the price of excellent scalability is that until your function is called, it does not launch. And when you need to run it, it can take up to a few seconds (cold start), which can be critical to your business/application.
What can be implemented in such an infrastructure?
Not every application is suitable for this. This thing won’t become a standard, it’s not the next step in technology, it’s not a holy grail, but it still has a very, very good niche that it fills.
You can’t do long-running tasks, because the vendor limits the time it takes for functions to run (Amazon allows up to 15 minutes). So we can’t take and run some web scraper and wait for it to parse sites within an hour.
We can’t deploy an application with a lot of dependencies because, again, since we have no control over the operating system where all this stuff spins, we may have problems with the libraries that rely on OS.
We cannot use global variables or any data stored in memory. And so our application must be kind of stateless.