When done correctly Serverless offers fantastic potential but can also lead to spectacular failure when critical concepts are overlooked. With over a dozen Serverless implementations on Azure Functions over the last couple years, I’ve learned some lessons the hard way. In this talk, I will be sharing a few of the most impactful hard-earned lessons and how I was able to overcome them. I’ll be touching on topics ranging from considerations using traditional relational databases, managing service and data connections to managing complexity and increasing observability. The talk is done in the context of Azure Functions but whose concepts apply equally to all Serverless Platforms.
2. About Me..
•Raleigh, North Carolina
•Developer & Consultant for 20+
years
•Engineer w/ AppDynamics (Cisco)
3. My Serverless Story
• Over a dozen Serverless implementations
in production today (Azure Functions).
• Along the way I’ve had surprises and
challenges.
• Sharing with you a few of my top
challenges.
• My context is Azure Functions but many
of the concepts are universal.
4. Those apples look good!
•Different Design Patterns
•New and Emerging Best Practices
•Quickly changing environments and
frameworks.
•Ease of implementation double
edged sword
11. Downstream: Do Nothing – Let the request fail.
• Utilize Dead Letter Queues (Poison Queues)
• Ok for occasional more transient issues
• Azure Functions Create Poison Queues Automatically (default 5 failures)
• Do something with the queues!
Requests
Requests-Poison
12. Downstream: Make your environment scale less
• Implement a more traditional queue based load leveling
• Azure Functions – Standard App Service Plans, Updates Host.json -
(WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT, queue specific
concurrency settings)
• AWS Lamda – Concurrent Execution Limits
• Application has to tolerate potential increased processing latency
13. Downstream: Schedule your message processing
•Schedule future enqueue time.
•Most messaging platforms support
scheduling future processing such as
Azure’s ServiceBus
•Careful with this technique or you may
bypass safety of poison queues.
15. Downstream: Adding Resiliency to your requests.
• Have your code allow for retries and other transient issues.
• Use exponential back-off to improve chances of request going
through.
• Careful not to extend your retries too long (execute time costs &
time limits)
• Share your retry attempts centrally to allow multiple instances to
be aware.
• Lots of popular resiliency frameworks - .net Polly.net
18. Downstream: Use a more scalable back end
• Great opportunity for green field applications.
• Consider a cloud native database that are able to scale and match
the throughput of Serverless
• Azure – CosmosDB
• AWS – DynamoDB
• Both Relational & NoSQL can scale - NoSQL can often have edge.
• Consider ease of implementation along with the other benefits
19. Azure CosmosDB
• Globally Distributed, Multi-model, NoSql Database
• Convenient integration with Azure Functions
• Not “Serverless” but with massive throughput available can scale
w/ Serverless
20. Connections are Important
• Typically client connections are intended to manage
a limited resource (connections, ports, etc)
• As Serverless scales those resources may be
stressed and may not always free up when you think
they do.
• Any *Client based class (HttpClient, SqlClient,
DocumentClient, etc)
• Be suspicious of “helper” libraries that may not
make the most efficient use of connections or don’t
align well with Serverless
21. Best Practices for Handling Connections
• DO NOT create a new client with every function invocation.
• DO create a single, static client that can be used by every function
invocation.
• CONSIDER creating a single, static client in a shared helper class if
different functions will be using the same service.
• Anti-intuitive but avoid Disposing.
• Even SQL Connections can benefit
23. Managing and Mitigating Complexity
• Serverless architectures can often be very complex
• Common asynchronous patterns such as messaging
add to the complexity
• Following the ”Single Function – Single Purpose” best
practice can require complex orchestrations.
24. Managing Complexity - Orchestration with Logic Apps
• Designer (no-code) based Serverless orchestratorworkflow
• 200+ OTB Connectors (Azure + External)
• Supplement with Azure Functions
25. Managing Complexity: Orchestration with Durable Functions
• Code based orchestration unique to Azure Functions
• Manage state in a stateless server environment
• Uses storagequeues behind the scenes
• Support for various common orchestration patterns
• Function Chaining
• Fan-inFan-out
• Async Http Calls (w/ status)
• Monitoring
• User Interaction (waiting for user interaction)
27. Azure Functions Bindings
• Declarative way for Functions to connect with Data
• Works with many common data sources in Azure such as queues,
storage, Event hub, CosmosDb
• Writetest less code == increased developer productivity
28. Honorable Mentions (Important but no time)
• As easy at it is in the beginning to “right-click publish” use CICD
pipeline such as Azure DevOps
• Implement your own “Chaos Monkey” so you understand your
monitoring tools and how to use them (or identify if you have).