A Reactive Microservice, one that must provide scalability and resilience, should own its own data and be able to act autonomously. An autonomous service must store all the data necessary for it to achieve its functions. Sometimes this data can be owned by other services and be stored in many places. Obviously, you cannot ensure consistency by stopping all requests in the entire system to allow one operation to finish. How do you design a system capable of dealing with these complex interactions?
Domain-Driven Design (DDD) is a proven modeling pattern in which business and technical experts cooperate to design the system around business needs. DDD offers a realistic way to establish boundaries and contexts for individual microservices. However, what has proved to be difficult for many is modeling the space in between microservices.
Events-First Domain Driven Design has emerged as modification of DDD that makes it easier to model data dependencies and communication across the system. Events are facts, things that will happen in the running system. For example, in an ordering system, the finalization of an order is an important event. During event storming, you would explore what leads up to that event. That might include, for example, queries about sales tax rates, selection of a shipping method, and validation of payment. This will help you identify the entities involved and draw the correct boundaries around them.
The events provide a record of what happens to each entity and when it happened. In a Reactive system, a microservice can publish events to durable storage, a so-called event log. Other microservices or external systems can then access those events. This helps by decoupling microservices from each other. The event log becomes a history that a recovering microservice can replay to recover and provides an excellent basis for auditing and debugging.
The challenge for developers new to an event-driven architecture is accepting the fact that when state changes, it takes an indeterminate amount of time before every component in the system sees that change. This is the tradeoff you make to achieve reactive characteristics and is referred to as eventual consistency.
In a traditional n-tiered architecture where functionality was tightly coupled and associated with a single database it was possible to maintain strong consistency. In a distributed system however, strong consistency limits scalability, availability, and throughput. A microservice design needs to identify where strong consistency is necessary — usually within a microservice — and where consistency can be relaxed.
The shift in paradigm to eventual consistency becomes easier when you realize that it more accurately reflects how the world works. The things we observe have already happened. And, workflows and state machines are common development practices that fit an event model.
Focusing on events and accepting eventual consistency allows for a variety of communication patterns in a microservices system.
“One of the major benefits of microservices-based architecture is that it gives us a set of tools to exploit reality, to create systems that closely mimic how the world works.”
In less than 15 minutes:
In less than an hour:
Really dig in: