Serverless Diary: Your Way to a Successful Event-Driven Architecture
I. Introduction
Carrying on from where I left sharing my experience of implementing microservices in a serverless style in my previous blogs, the focus of this blog is to understand how to approach event-driven design. This blog takes the understanding of core principles of event-driven architecture and demonstrates how to use them in your serverless architecture.
II. What and Why of Event-Driven Architecture
Event-driven architecture (EDA) can be seen as a way of wiring all your microservices together. In this architecture, a microservice publishes an event when something notable happens, such as when it updates a business entity. Other microservices subscribe to those events. When a microservice receives an event it can update its business entities, which might lead to more events being published.
In the last decade, event-driven architectures have gained more popularity as more organizations and businesses have moved to the cloud. In the context of serverless cloud-native architectures, where the goal is to move to more managed services without worrying about manual intervention for scaling your infrastructure, I find event-driven architecture usage more compelling because of the following benefits:
- Automatic Scaling — Since individual components in your serverless landscape are capable of auto-scale. Bottlenecks due to increased load or traffic are identified and taken care of automatically by the virtue of managed service usage, wherein only your affected component auto-scales and not your entire infrastructure.
- Asynchronous style Communication — avoids all bottlenecks caused by synchronous architectures where an increase in traffic is proportional to the responsiveness of your application.
- Decoupled — Each microservice/component can be independently developed, tested, and deployed, helping with business agility and speed to market.
III. How to do Event-Driven Architecture
The event-driven architecture is not a new style of architecture. A common way of implementing this style involved using messaging brokers and queues before the cloud era. The main challenge with those implementations was that the message brokers became a single point of failure and were usually managed and developed centrally at the enterprise level. The result was coupled implementations and complex releases across projects, increasing the blast radius in case of a disaster.
Let’s understand the modern serverless way of achieving event-driven architecture, yet highly scalable, available, de-coupled, and fault-tolerant. There are several flavors and patterns of achieving this using AWS serverless services. I will stick to the most common use case pattern. Let’s explore figure 1, which is an extension/development over our previous blog.
Let’s break down the official definition in-line with the above diagram. As per wiki, EDA is a software architecture paradigm that promotes the production, detection, consumption of, and reaction to events.
- Production of event: The API gateway (1) is triggered in response to a POST/PUT request made by an application (frontend or backend) that invokes the producer microservice (2). The lambda performs an Insert/Update/Delete operation on the dynamo generating an event.
- Detection of event: The DynamoDB Streams (3) captures a time-ordered sequence of item-level modifications in the DynamoDB table and stores this information in a log for up to 24 hours. The event data is streamed to the destination lambda responsible for publishing this event (5) to an event stream (SQS in this case). SQS adds the benefit of de-coupling, durability, and fault tolerance for this architecture.
- Consumption of event: The consumer microservice (6) is polling for new messages and reliably receives all the queue messages. In case you have multiple consumers (>2), update the above design to implement a fanout pattern, wherein step 5 will publish an event to an SNS topic. Based upon the number of consumers, you can have multiple SQS subscribed to the SNS topic.
- Reaction to the event: The consumer microservice (6) receives the message and performs the needful business operation.
III. Challenges / Gotchas
- End-to-end monitoring and tracing can become very challenging in EDA. To avoid operational nightmares, The development team must understand the importance of logging and implement relevant success, error, warnings with meaningful information ( including a correlation id to join everything together). Enabling X-rays is a huge help, but sadly that’s not enough as there is still some work AWS needs to do to provide tracing across all services seamlessly. Till AWS gets it perfect, let’s implement proper monitoring controls based upon error and warning codes logged by the individual microservices.
- Exception Handling: Exception handling of web-facing microservices is still relatively easy and forgiving. But with events firing asynchronously in the backend for EDA, incorrect or lack of proper error handling can be quite devastating. Few examples from figure 1:
a. In step 4, configuring a DLQ for the destination lambda is extremely important. The lambda will stop processing any data in the impacted shard for 24 hours if it encounters a corrupt payload. The payload then gets discarded from the DDB(DynamoDB) stream.
b. Step 7 is a slight variant of the previous example. This step of having a DLQ configured with the original SQS ensures that after exceeding maximum retries of delivering the message, the message moves to the DLQ. Discarded messages can be analyzed and acted accordingly. - Visualization/Debugging of architecture: The event-driven flow is not explicitly modeled and exists only as an emergent property of what the system does. This view exists in the mental model of the architect that understands the end-to-end interaction. Debugging through the code to gain an understanding of various component interactions isn’t easy and always possible. Hence its extremely important to document EDA’s properly.
Final Reflections and takeaways:
If you have been following my serverless blogs, you would have realized I am a big promoter of serverless style architectures. There are numerous benefits to designing serverless architectures. Not denying the challenges it bring, but to move forward and up the chain of abstraction, we work around these challenges. Serverless designs are like joining various lego pieces together and offer infinite possibilities. Let the priceless principles and patterns accumulated over the decades guide you into the creative world of serverless architectures. Just remember you are not limited to the best practices available to date. Be innovative and brave to implement niche practices and patterns, providing future generations a richer catalog than that exists today.