Creating a distributed software system based on Service Oriented Architecture (with Microservices implementation technique as a possible approach, more on this here) very quickly presents a question of communication between the services in the system. Communication choice may greatly affect non-functional requirements such as stability, availability, reliability, maintainability and other “-abilities” of the system.
To increase your chances of success it is important to understand that SOA based software systems require communication that promotes autonomy, spatial and temporal decoupling, reliability.
Let’s look at a point-to-point (direct) communication pattern, which often is promoted by various vendors and Microservices evangelists. The premise is very simple – create microservices that “do something small” and let them talk to each other via some sort of an RPC protocol (underlying technology doesn’t really matter). Let’s look at how that behaves and quickly identify potential pitfalls with such approach (see video below):
As you can see, there are few major issues with such communication style:
- Spatial coupling – requires services to be aware of each other, and able to reach out to each other
- Temporal coupling – requires services to be present at the same time in order to ensure successful operation
- Failure of a single component may take down most if not all of the system, causing cascading failures and unavailability of functionality to customers
- Development and deployment coupling – high probability of a change in one service causing cascading changes in other services, complex orchestration during development, testing and deployment into production
- High probability of introducing distributed transactions for situations where services boundaries are not properly defined
The disadvantages are quite obvious yet there are a lot of projects that default to this style of communication with engineers blaming the failures (caused in part by this choice) on selected implementation technique.
Now, if we consider services boundaries and the factors that come from that, we quickly realize that our needs for cross-service communication are greatly reduced – our business transactions are encapsulated within a single module that works or fails on its own, with no dependency on anything else. This means – a service never needs to reach out anywhere outside of its boundaries to fulfill its purpose.
Once we consider such service autonomy, the communication needs change dramatically. This is where Event Driven Architecture comes into picture and the synergy of SOA and EDA produce a powerful combination – ability to notify the system about a change in a service’s state via events, which promotes much lower coupling between components.
Let’s look at a pretty standard sequence of steps happening in such environment:
- A business transaction gets initiated via a request from a user or another component / system
- A service fulfills a business transaction, which results in the change of its state.
- The state change is announced – anyone interested in this specific change gets a notification with details of the change
To enable EDA we need to have an infrastructure that provides a mechanism to publish and consume notifications. One of the most obvious choices in this situation is a message broker or a service bus.
The benefits of such approach:
- Service autonomy is much stronger promoted due to constrains imposed by communication style
- Spatial coupling is no longer present – services don’t need to know about each others location
- Temporal coupling is eliminated – there is no need for one service to be running at the same time as others
- Failure of a single component leads to a degraded system performance, not a cascading failure of multiple components
- Development time coupling is greatly reduced, deployment coupling is virtually eliminated
- Distributed transactions are still possible as they are a result of an incorrect services boundaries, however this communication style makes them more obvious and visible, thus allowing for design corrections
What are the most obvious drawbacks of introducing messaging into the mix? Well, there are at least the following:
- There is another technological artifact to deploy, monitor, maintain, which really means extra cost.
- If your organization doesn’t have ESB (message broker) this would be a new piece of technology
- Monitoring tools and processes to ensure issue resolution
- Communication pattern requires different ways to respond to failures – dead letter queues, component recovery, etc.
- This is a compromise to enable overall greater system availability and reliability
- Different programming mindset and model
- Really is needed regardless to ensure successful design and implementation of an SOA based distributed software system
I think the event based model you have described is very practical. I am wondering however whether it is a reasonably complete solution.
An object may contain data made up of contributions from various services that cross the boundary of aggregates. Such shared objects are the reality of every business domain. Now if such an object is involved in a transaction, won’t this necessitate distributed transactions & multi-phase commit?
Take a human, for a example. You. To your employer you are an employee with specific attributes (salary, seniority, department, manager, etc.). To your doctor you are all about your health history, medication, etc. To tax office – it’s all about your income and taxes paid. And so on.
Each entity within a domain very often has specific meaning in various subdomains, however the only bit of information that is really shared there is its Identity. An entity gets created somewhere – a human is born. And after that fact, all other subdomains may start building their own view of the entity.
You don’t have multiple subdomains that *own* same pieces of data for a given entity.
If your subdomain needs to know some bit of information from another subdomain – nothing is stopping you from storing that bit in a *view model* (read only cache that gets updated via processing notification events).
Hope this helps.