dotnet-architecture / eShopOnContainers

Cross-platform .NET sample microservices and container based application that runs on Linux Windows and macOS. Powered by .NET 7, Docker Containers and Azure Kubernetes Services. Supports Visual Studio, VS for Mac and CLI based environments with Docker CLI, dotnet CLI, VS Code or any other code editor. Moved to https://github.com/dotnet/eShop.
https://dot.net/architecture
24.53k stars 10.35k forks source link

[Question] Doesn't EventBus and CommandBus Abstraction Tightly Couple Services? #506

Closed MikahB closed 6 years ago

MikahB commented 6 years ago

Apologies if this is a poorly-formed or irrelevant question, I'm working hard to understand Microservices architecture and it's foundations in DDD.

Based on what I'm reading, it seems like referencing the common EventBus and CommandBus projects from each microservice couples them more tightly than they should be and creates a SPOF. Is this just done in this example as one option, or is this how an enterprise-grade application should be built?

I understand the Buses themselves are common, but if someone tweaked those projects you could impact all services based on them. Maybe the buses being common overrides the need for separation here? Appreciate any insight into this small piece of a large puzzle.

CESARDELATORRE commented 6 years ago

Of course, and this is a very good question. Not a "poorly-formed or irrelevant question" at all. The point is that whatever is shared across microservices should be artifacts like "standard libraries", Nuget packages, "building blocks" that should be generic enough. It is like sharing a NuGet package for JSON serialization (i.e. Newton JSON serializer), or sharing a client API from Azure SDK in order to work with Azure Service Bus or API for Azure Storage Blobs, etc.

It has to be the kind of stuff you would create NuGet packages to be re-used across different applications and even different customers because it is a generic artifact that shouldn't be changing constantly as the application evolves. However, it is clear that a team needs to be responsible for those building blocks in the same way that a team is responsible for any public and published NuGet package or SDK.

On the other hand, you shouldn't share simple "common code" across microservices because that would impact their autonomy. But it is ok to share libraries or NuGet packages that are generic enough, meaning generic enough even for different applications or customers.

In a production project you would convert those building blocks to Nuget packages. We're not doing so because we want the community to explore that code, too.

About SPOF. Well, not really. In production you would use a scalable system like Azure Service Bus which is high available, so it is not a SPOF like a single RabbitMQ container that we use only for Dev/Test environments. You could also create a HA RabbitMQ environment, but that will be IaaS, more infrastructure complexity to make it high available and scalable. But that is an option, too.

I hope the differences are clear enough. And again, very good question because as a general rule, in microservices is more important to favor autonomy than just trying to re-use any kind of code. DRY must be taken with care across microservices. But this case, an Event Bus or any "public" NuGet package, are exceptions because those components should be generic.

CESARDELATORRE commented 6 years ago

Closing this issue but feel free to keep commenting about it, of course. :)

MikahB commented 6 years ago

Cesar - thank you for the excellent, detailed response! That does make a lot of sense!

CESARDELATORRE commented 6 years ago

And by the way, the important point here is about asynchronous communication (with eventual consistency) between microservices. For some cases, instead of using messaging like the Event Bus, you could also achieve a similar "asynch" communication by polling with HTTP from the destination microservices. Sure, HTTP is synchronous, but polling for changes creates an "async communication" because you are not creating long HTTP cycles when the client app makes the query. Take a look to this page where I explain this topic end-to-end: Look for the section "Asynchronous microservice integration enforces microservice’s autonomy" https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/architect-microservice-container-applications/communication-in-microservice-architecture

The event-bus would be the second case. Http Polling would be the last case. image

MikahB commented 6 years ago

Cesar - thanks again for more details. I will read through that document in its entirety.

I'm currently using RabbitMQ IaaS for my buses (I have 4) and only HTTP between the App and gateway API. My application reads from industrial sensors where there are many opportunities for failure so I'm comfortable with the benefits of async and eventual consistency - those feel natural to me.

My commitment to learning and building microservices for my new company (which I am bootstrapping) is due to having lived first hand the pain of BBoM enterprise applications and how they essentially trap a company into an irrelevant tech stack (3M lines of code in a PowerBuilder application? Good luck to ya!!). So, I'm just trying to be extra cautious I don't charge off half understanding what I'm doing and end up with my own new BBoM with a few chunks in it that were supposed to be microservices!

CESARDELATORRE commented 6 years ago

Very interesting. Please feel free to keep submitting questions into the repo. Even more, when you think you'd have significant feedback, I'd be willing to handle a call where we could discuss approaches and you could provide your feedback about your experience and what approaches could be improved, etc. ok? Whenever you want to have that call for providing feedback, send me an email to cesardl at microsoft.com, so we plan about it, ok?

MikahB commented 6 years ago

Perfect Cesar, I will definitely follow up with you for sure and keep watching / asking here if needed.