It’s a while i’ve hands on distributed architecture and cloud , but somehow i was so surprise by serverless, kind of WOW i hate servers (i love containers yet), i was wondered about how well can we use a serverless architecture and in this article i would like to talk about some best practices and complexities of this architecture.
What is Serverless?
If you are a novice to that , the serverless is simply taking a container in which you run a small piece of code, you don’t care about where, how and when to deploy, just call it.
Behind the scene:
A container is raised and your application’s code will be deployed to it, the code will be executed , the result fetched and the container goes off(not simple as this but don’t worry i’ll explain that).
It’s enough easy to design a serverless architecture but you need some kind of best practices to handle it’s challenges and all of these challenges are based on cloud architecture pillars.
- Tracing (Operational excellence pillar)
- Versioning (reliability pillar)
- Cold Start (performance pillar)
- Cost (cost pillar)
- Security (security pillar)
It’s hardly needed to track and trace the operations in any serverless architecture, logically when using Cloud the providers will provide their clients the basic monitoring(ex. Azure monitor or aws cloudwatch), but it’s not enough , this is a simple Begin/End request logs with a correlation id which in most cases can not help you find your problematic.
Add Logs : by adding the logs in your Lambda function or azure function code and adding business valuable logs. Finally create a dashboard to have your application state. a meaning full customized metrics (ex. requests number, items treated, cost overhead, cost calculated monthly)
Categorized logs: Try to define meaningful resource groups based on platform, application, route or business language, this way you can easily detect a failure or bottleneck in your application.
Thresholds: define some thresholds in your monitoring system to alert or do an action, try set the thresholds based on severity levels so if it reaches that max number of failures in your system
Alerts: it can run the action you have already defined (ex. send email or sms, throttle ip address, rollback to last version of code) to stop the business failure.
As you do versioning in any web or desktop application, Api or mobile app, you need to do it also in a serverless architecture, we don’t have the servers but any kind of Code, Resource or configuration shall be versioned to obtain the recovery automation. Separate the application code from Infrastructure and don’t mitigate the development phase by mixing these parts, it will cost the difficulties later.
Package: deploy your package based on a convention and restrict all access rights to that and implement RBAC to achieve security.
Clean Up: don’t try to remove already deployed packages but do kind of retention period process to archive or delete unnecessary and old ones to avoid storage costs.
Function is not a route: never change the function name by version, don’t add version number in the name. don’t look at the function as a web method.
Every function is deployed in a container , the first time you call the function it’s compiled, deployed and executed, finally it stays alive for a short period of time(idle timeout) and it will be destroyed after this period.
Keep it small: As the function need to be initialized before execution keep your code package as small as possible, remove all unnecessary dependencies or libraries charged by default if you don’t need them.
Keep all close: If you need to install the dependencies like Nuget packages, try using AWS Lambda Layers or Azure Package Registery, so your initialization time will win against network latency, OR include the dependencies folder in your package.
Memory can help: when creating a function you need to define the memory which is allocated to your function, this amount of memory can affect the initialization time for statically typed languages like java and C#. higher memory can reduce cold start but be aware of idle timeout, the higher memory is set the sooner the function will be destroyed.
An anti-pattern : I don’t propose to do that but running docker in function can reduce the function cold start, but the functions has a disk space limitation so you can not run a docker as Microsft windows for .Net which is about 400 or 500 MB(FYI: the docker need root access and it’s not simple to have it in function)
Choose Programming Language: instead of using a compiled language as c# which needs the jitting process use Node.js , Go, or python.
Keep it small : As the serverless functions are calculated by memory usage, execution time and you need to keep them enough small to not overcome the max defined resource limits. keeping in mind that the costs are calculated from initialization start time to the end, so considering a fast and small function can help you gain against the costs.
Define memory carefully: Th functions have allocated memory that you define and you are charged by that, defining a fine grained memory will help you in long-term.
Don’t warm it, keep it fast: Don’t invoke function by empty calls to keep it warm, instead try the best practices to reduce cold start, periodical or permanent invocations cost you as you don’t know when your function will be destroyed.
Usage Plan: Choose a usage plan more convenient with your needs as Consumption or dedicated, AWS lambda is a Consumption plan but Azure propose also App Service plan , consider use the best that fits your design and business, but know that with App service plan your function will not be killed as the execution is terminated and you will be charged a small amount for the idle resources as it will scales down to zero(as Microsoft says).
The Serverless is the the best in term of Scalability, Security and Cost but taking care of the security is always a deal in any architecture.
Http: Avoid runing functions on HTTP but if you need use OAuth using AD or any identity providers.
RBAC: Use Role Bases Access Control as when as it covers your needs. restrict function invocation to reliable services you own.
DDOS: In a provisioned server you can use IDS/IPS compliant services but as serverless functions does not have the IDS/IPS integrated services by theirs serverless design if you need call your function by public pass it via a kind of Gateway such as AWS Api Gateway or Azure Gateway.
Credentials: Any function has the credentials as environment variables or some sort of variables, so a compromised invocation may use some packages which have security holes so they can send your credentials to a chosen destination.