Event-driven architectures

An event-driven architecture is a software design pattern in which microservices react to changes in state, called events. Events can either carry a state (such as the price of an item or a delivery address) or events can be identifiers (a notification that an order was received or shipped, for example). The events trigger microservices that work together to achieve a common goal, but don't have to know anything about each other except the event format. Although operating together, each microservice can apply a different business logic, and emit its own output events.

An event has the following characteristics:

  • It is a record of something that has happened.
  • It captures an immutable fact that cannot be changed or deleted.
  • It occurs whether or not a service applies any logic upon consuming it.
  • It can be persisted indefinitely, at a large scale, and consumed as many times as necessary.

In an event-driven system, events are generated by event producers, ingested and filtered by an event router (or broker), and then fanned out to the appropriate event consumers (or sinks). The events are forwarded to subscribers defined by one or more matching triggers. These three components—event producers, event router, event consumers—are decoupled and can be independently deployed, updated, and scaled:

Event brokers and subscribers

The event router links the different services and is the medium through which messages are sent and received. It executes a response to the original event generated by an event producer and sends this response downstream to the appropriate consumers. Events are handled asynchronously and their outcomes are decided when a service reacts to an event or is impacted by it, as in the following diagram of a very simplified event flow:

Event-driven architecture

When to use event-driven architectures

Consider the following usages when designing your system.

  • To monitor and receive alerts for any anomalies or changes to storage buckets, database tables, virtual machines, or other resources.
  • To fan out a single event to multiple consumers. The event router will push the event to all the appropriate consumers, without you having to write customized code. Each service can then process the event in parallel, yet differently.
  • To provide interoperability between different technology stacks while maintaining the independence of each stack.
  • To coordinate systems and teams operating in and deploying across different regions and accounts. You can reorganize the ownership of microservices. There are fewer cross-team dependencies and you can react more quickly to changes that would otherwise be impeded by barriers to data access.

Benefits of event-driven architectures

These are some of the advantages when building an event-driven architecture.

Loose coupling and improved developer agility

Event producers are logically separated from event consumers. This decoupling between the production and consumption of events means that services are interoperable but can be scaled, updated, and deployed independently of each other.

Loose coupling reduces dependencies and lets you implement services in different languages and frameworks. You can add or remove event producers and receivers without having to change the logic in any one service. You don't need to write custom code to poll, filter, and route events.

Asynchronous eventing and resiliency

In an event-driven system, events are generated asynchronously, and can be issued as they happen without waiting for a response. Loosely coupled components means that if one service fails, the others are unaffected. If necessary, you can log events so that the receiving service can resume from the point of failure, or replay past events.

Push-based messaging, real-time event streams, and lower costs

Event-driven systems allow for push-based messaging and clients can receive updates without needing to continuously poll remote services for state changes. These pushed messages can be used for on-the-fly data processing and transformation, and real-time analysis. Moreover, with less polling, there is a reduction in network I/O, and decreased costs.

Simplified auditing and event sourcing

The centralized location of the event router simplifies auditing, and lets you control who can interact with a router, and which users and resources have access to your data. You can also encrypt your data both in transit and at rest.

Additionally, you can make use of event sourcing, an architectural pattern that records all changes made to an application's state, in the same sequence that they were originally applied. Event sourcing provides a log of immutable events which can be kept for auditing purposes, to recreate historic states, or as a canonical narrative to explain a business-driven decision.

Architectural considerations

An event-driven architecture might require that you approach your application design in a new way. Although well suited for applications that make use of microservices or decoupled components, you should also consider the following:

  • Can your event source guarantee delivery if you need to process every single event?

    It should be a durable and reliable event source.

  • Can your application handle multiple asynchronous requests?

    Your system performance shouldn't rely on global scope or inelastic databases.

  • How do you want to track your event flow?

    An event-driven architecture supports dynamic tracking using monitoring services, but not static tracking using code analysis.

  • Do you want to use the data in your event source to rebuild state?

    You should consider how to ensure that your data is deduplicated and ordered.

What's next