A Journey from WebApi to Azure Functions
Going through achievements for last year, I would like share my introduction to serverless.
I would like to start from the helicopter view: we had a MVP project implemented as a dozen of .NET WebAPI
(.net core 3.1). Services are supposed to be resilient and scalable. The initial idea was to have them running on Kubernetes
cluster. Sounds nice and simple? It does, in theory... we quickly find out that the system is heavily depends on the platform in this case Kubernetes
. Which means, every noise happens in the cluster having direct implication on services its running. These are couple of things to consider next time while choosing orchestration strategy in future:
First, you still will have to manage Kubernetes
cluster though it is managed. There is no setup and forget shortcut here, Kubernetes
is a complex platform. Even if you are going to spend half an hour a day for monitoring your cluster and checking the alerts, it is still relatively big effort.
Secondly, cloud provider, Azure in our case, forces you to do upgrades of managed Kubernetes
from time to time. Yes, you will be notified a couple of months before, but honestly, you can't prepare yourself for unknown. If you did update Kubernetes
cluster in production once, you might understand this feeling of uncertainty. You can never know what of your services will run after the upgrade. Not to mention custom cluster's internal services like dns, networking and etc, it can easily become a nightmare.
Thirdly, service meshes are tricky. We introduced istio as a service mesh for the cluster to improve observability, security and monitor internal communication between our services. It is definitely very powerful tool, however we faced a several problems with customization. The reason is that most of these tools still shipped as a beta, which can mean couple of bugs and lack of documentation and community support. It is quite straight forward implemeting the standard use cases, but when implemeting custom things its getting worst. Introduction of such infrastructure tool for you system can only enhance two points mentioned above.
This situation just supported skepticism about the correctness of choice we made for Kubernetes
. For intensive system a high availability is major quality attribute. Kubernetes
is so complex and so modular system that it takes a quite effort to tune it for specific needs. The effort resources and learning curve we didn't have.
We've decided going for Azure Functions
and serverless as a target architecure for several reasons:
- We don't actually need to monitor and maintain the platform (k8s in our case)
- We can easily scale up if needed every component separately.
- With serverless we do not share same platform. Yes, it might be running on same Azure server internally after all, but still its Saas (Function as a service) and not Paas.
- Simple deployment comparing to container approach - just build and copy files. Which allows us roll out services in minutes regardless region.
Migration to Azure Functions
was easy though. We introduced our selfs to a new dotnet-isolated which was super easy to setup. The dotnet isolated mode allows you to enjoy recent .net features were lacking in previous version of Azure functions
such as dependency injection. for more about dotnet-isolated refer to this guide.
Here is a several things we had struggled with:
Different mind set - at first glance not obvious point. Serverless requires different way of thinking when it comes to structuring your logic specially for long running methods. There are couple of limitation you should be aware of migrating to Azure Functions, execution duration limit and amount connections limit. Best example is a worker that gets data from database, processes it and saves back to the db. No-brainer solution might be wrapping your code in one console app and declaring hosted service that fetches data from database, processes and saves, pr. However, for serverless approach, depending on the load of course, it will not work this way due to duration limitation and maybe connection limitation as well. You will have to split into several functions and maybe with introduction of message queue in the middle: one function gets data from database sends it to processing queue, second function picks up messages for processes and saved them.
Bigger Devops effort - considering the above you will probably split your function to several smaller and for each of them CI/CD should be created. The more functions you create, the more devops efforts you need.
Shared logic - suppose you have 20 different functions structured in 20 different projects according to
Microservices
notation. All of them uses same code snippets that you naturally don't want to replicate x 20 times. When you go for shared nuget package, and everything is clean and nice. However, besides obvious advantage this also will have own downsides e.g. every time you improve/fix this shared code you will have to update and redeploy all 20 projects.Learning curve - you will need some time to bring your functions to production ready state polishing middlewares, logging and metrics.
As an outcome I would say I'm rather happy with the choise. However do not consider serverless (microservices) as a "silver bullet" solution for everything. We did found relevant arguments for the migration, so you should.
The End
🚀 Turbocharge Your Infrastructure with Our Terraform Template Kits! 🚀
🌟 Slash deployment time and costs! Discover the ultimate solution for efficient, cost-effective cloud infrastructure. Perfect for DevOps enthusiasts looking for a reliable, scalable setup. Click here to revolutionize your workflow!
Learn More about Starter Terraform Kits for AKS,EKS and GKE
No comments are allowed for this post