During the year 2024, I have been presenting how I integrated a company central bus into a set of serverless distributed services. I have also written some thoughts down, and you can find them here
When I talk about a Microservice architecture I am thinking immediately at:
- loosely coupled services
- well-defined boundaries
- communication through lightweight protocols
When working with Microservices, I usually use Event-driven architecture (EDA). This combination becomes clear when I consider a complex distributed system in which some data is duplicated in multiple services.
For more info, I suggest reading:
When I design an application, I usually have multiple domains within my boundaries. Sometimes, my services must communicate outside my boundaries, for example, with other teams, and because of this, it is important to distinguish between the types of events:
- private/internal events
- public/integration events
For more info Internal vs External events
A team can own multiple microservices, each of which can be formed of various components and communicate with each other.
It's important to be aware that microservices that rely on a central bus to communicate their private/internal events can potentially lead to problems.
When a microservice sends events to the entire system, it broadcasts its internal state changes, which can leak business rules and expose its internal state.
This is different from how microservices are meant to work.
- Their internal details should not be exposed to other services.
- If other services start to rely on these events to function correctly, this can lead to tight coupling between services.
This is problematic because if the service's internal workings change, it can break other services that depend on those events.
The solution is to move to an EventBus Mesh.
Each team has one central bus, which sends events in and out with the company's central bus.
All the services within the team do not know about the existence of the company's central bus. They only know about their local bus and communication within the services is made with the local bus, which routes the event to the team bus.
The key aspect to focus on is setting clear "boundaries".
This mechanism is similar to Pub/Sub, but I subscribe to a Bus instead of an SQS Queue or SNS Topic.
Utilising an EventBusMesh allows me to control the publishing and subscribing of those events while maintaining isolation.
This approach helps to ensure loose coupling between services and enables each service to evolve independently.
The EventBridge Mesh design can be quickly implemented using Amazon EventBridge because it allows configuration of EventBridge to send and receive events between event buses in AWS accounts within the same region, across all regions, and between accounts in different regions as long as the destination region is a supported cross-region destination. When configuring EventBridge to send or receive events between accounts, you can specify which AWS accounts can send to or receive events from the event bus in your account. Additionally, you can allow or deny events based on specific rules associated with the event bus or events from particular sources. This is very important because, without an explicit denial, this design will not block a private event from reaching the company bus. By using IAM policy conditions in Amazon EventBridge I can add a policy to deny specific set of sources and event types.
EventBridge references:
- Using bus-to-bus event routing with Amazon EventBridge
- Sending and receiving events between AWS accounts in Amazon EventBridge
Conclusion
Hopefully, with this post, the EventBus Mesh pattern becomes clearer. By using Amazon EventBridge in combination with Amazon EventBridge Pipes, I gained the ability to connect multiple features and achieve isolation and control when publishing and reading those events. A clear drawback of this pattern is that putting events onto another bus is charged at the same rate as other put events operations. On the other hand, I didn't have to write any code except for the infrastructure configuration required for different types of buses. The extra charge on the Put operation is cheaper than writing your code to achieve similar isolation with other busses, such as Kafka to Kafka.
Top comments (0)