The Future of Software With Serverless .NET
Today, two main approaches dominate how we build processing units in distributed systems. The server-first approach relies on pre-configured infrastructure managed by the developer, whether it’s a VM or a container, and typically runs 24/7.
The serverless approach, by contrast, shifts infrastructure responsibility to the cloud provider. Instead of provisioning and managing servers or containers, you rent compute units that execute on demand and only pay for each usage.
Serverless units are like cloud functions. They spin up only when triggered, process their task, and shut down. This makes serverless highly cost-effective for specific workloads, but not for all. For example, these units can introduce latency during start-up times, making them unsuitable for systems sensitive to latency.
In this article, we’ll discuss the core features of serverless architecture in .NET, explore the most common tools, such as Azure Functions, and examine the real-world tradeoffs between serverless vs. server-based software architectures.
What Is Serverless Architecture in .NET?
How Serverless Works With .NET
A serverless unit implements the function-as-a-service business, meaning we can rent a service similar to a function call in the code. It works by turning the server up to accept a request in the network, processing the response to the client, and then going offline again. Hence, it stays in a sleep mode, not generating any costs, until a request gets to it.
Although its name suggests otherwise, serverless works by letting the cloud provider manage a server on which the application code runs. For instance, when we rent a service like Azure Functions with .NET, we receive a pre-configured unit to process to run the source code. In contrast, in server-first approaches, we need to configure a web server such as .NET Kestrel, and containerize it into an Azure Virtual Machine with the source code.
Benefits of Serverless for .NET Applications
As mentioned, serverless functions stay asleep until a request comes in. During that time when a function is not receiving traffic, it doesn’t generate costs with the cloud provider. This is an excellent benefit in architectures that prioritize cost optimization.
A typical event-driven workflow can take advantage of how serverless functions work, like in asynchronous event pipelines, where the user doesn’t need a response in real time. In such scenarios, we can design algorithms that take minutes or even hours to complete, and the serverless startup time itself doesn’t add much to the latency account.
For instance, imagine a machine learning pipeline that identifies all action scenes in a movie in video streaming businesses to recommend movies to users. Hence, it could take a long time to validate, transform, and process the entire video. Therefore, intermediate steps, such as validation and input transformations, could be a set of Azure Functions without impacting the user experience.
Thus, one great use case for leveraging .NET serverless architecture is when we don’t need to result in an online/real-time fashion, since it incurs less cost.
Serverless Limitations and Tradeoffs
One limitation of serverless functions is when the system needs to respond to the user in real time. By using serverless in such cases, we’re adding latency to the request due to cold-starts, which slows down the user’s response, negatively affecting the user experience. Even though the costs from serverless are typically lower than server-first approaches, it might not pay the price of having fewer users on the platform due to the system’s slowness.
In cases where a platform needs to work 24/7 (or close to that) to respond to the user, the server-first approach is more available since the server doesn’t shut down if there’s no incoming traffic. This creates less latency due to fewer start-ups and makes the user happier.
Of course, anything is possible as a serverless function at the backend is simply a server managed by the cloud provider running the application code. However, for business products, the balance of cloud costs vs. user experience tends to be heavier on the user experience side.
Finally, serverless creates limited control over the server configurations since we simply call a function to get a response. In a traditional server-first approach, we can customize almost all server configurations if we need to.
Hybrid Serverless Strategies With .NET
From previous sections, we understood serverless functions and when it’s better to use a server-first approach instead of serverless. This section explores combining the two to into a hybrid serverless architecture that takes the most advantage of both tools.
Combining Serverless and Traditional Servers
We’ve seen that serverless is most suitable in cases where latency is not a problem. On the other hand, server-first approaches respond faster and perform better in latency-critical systems. The good news is that many business use cases can be designed as a hybrid architecture to let the end user interact with server-first, while the background jobs and processes leverage .NET serverless functions.
For instance, let’s imagine again a video streaming platform. Our platform needs two main features: a media player and a movie recommendation system.
The first lets the user interact with the media player, like playing, pausing, going back, and going forward. This feature is a latency-critical requirement since the user wants the action to take effect instantly. The second feature is a movie recommendation system that shows the user on his home screen more movies similar to his historical streaming data. That requirement is non-latency-critical since the user can still use the core features without their real-time recommendations. At some point in the future, he’ll get his recommendations.
From a technical perspective, the first feature could leverage a server-first application to respond faster to the user interacting with the media player in real time. Since there are no startups, the latency is smaller, positively affecting the user experience. On the other hand, the second feature could be a set of serverless functions connected via queues to process the user’s historical data and recommend movies asynchronously.
Best Practices for a Hybrid Approach
Although a hybrid approach with server-first and serverless is possible, we must take extra care with some aspects, especially observability and coupling.
From an observability perspective, having a centralized dashboard of metrics is essential to translate the server and serverless worlds into digestible business metrics. For instance, it’s important to understand whether the user can click the play button without errors, and whether the movie recommendation system algorithms finished correctly.
Additionally, it is crucial to separate concerns between the server-first and serverless worlds. Let’s imagine, for instance, if the media player service depends on another service B that depends on a serverless service C. Even though the media player doesn’t use a serverless architecture directly, the latency from its dependencies will impact the final user experience. Therefore, decoupling the server-first and serverless workflows is crucial for one not to impact the other in hybrid architectures.
Serverless Tools and Platforms for .NET
Now that we understand serverless vs. server-first vs. hybrid architectures, let’s examine the tools available on the market to create such architectures.
Azure Functions and Durable Functions
The first tool we’ll cover is Microsoft-native Azure Functions. Azure Functions are serverless units that have native support for .NET applications, making them a good candidate for teams already adopting .NET.
Also, Durable Functions let the developer create stateful serverless functions. This means that the function keeps an internal state and does not only return an output from an input. In practice, this is helpful to create patterns where the developer needs to keep the function state in an asynchronous workflow, like async HTTP APIs.
Also, it’s important to mention that Microsoft had some work done last year to improve the cold start time of Azure Functions, reducing its latency by 53%.
AWS Lambda for .NET
Another option is the AWS Lambda functions using .NET SDKs. AWS supports .NET Core applications natively. However, for .NET 6 or higher, the support comes from configuring either a customized runtime or a container image.
It is a good choice for teams already in AWS because it is seamlessly compatible with different AWS cloud services, such as Route 53, S3, and DynamoDB. However, the setup can be more complex than with Azure for applications using .NET.
Google Cloud Run Functions
Google recently added support for .NET in its Cloud Run serverless functions, making it another competitor in the serverless market.
Below, the table summarizes some aspects of serverless functions from AWS, Azure, and GCP, in order to make the best choice for your architecture.
Feature | AWS Lambda | Azure Functions | Google Cloud Functions |
Invocation Cost | $0.20 per 1 million requests after the first 1M free per month | $0.20 per 1 million executions after the first 1M free per month | $0.40 per 1 million invocations after the first 2M free per month |
Compute Cost | $0.00001667 per GB-second | $0.000016 per GB-second | $0.0000025 per GHz-second and $0.0000100 per GB-second |
Cold Start Time | Typically under 100 ms to over 1 second | Typically 1–10 seconds; occasionally up to 30 seconds | Typically 10–15 seconds; improvements with CPU boost |
Free Tier | 1M requests and 400,000 GB-seconds per month | 1M executions and 400,000 GB-seconds per month | 2M invocations per month |
Provisioned Concurrency (faster start-up and processing time) | Yes (additional cost) | Yes (Premium Plan) | Yes (Minimum Instances) |
.NET Support | .NET Core and .NET 6+ via custom runtimes or container images | Native support for .NET languages | .NET Core support via custom runtimes |
Conclusion
The discussion between server-first and serverless is broad, and it’s essential to understand both in detail, so we don’t fall into architecture traps.
In this article, we’ve seen the difference between server-first and serverless architectures with examples. We’ve also covered some tools available on the market to create serverless architectures.
In addition to understanding that difference, developing functional and scalable solutions with these technologies is essential. Thus, to help in your journey, hiring an experienced and reliable partner such as Chudovo is highly beneficial. They hire the top 1% developers in the market to produce .NET architectures and applications that have already driven different businesses to success.