8

As far as I know, there are two commonly used patterns when dealing with services communication in a microservices architecture:

  1. Direct-calling other services. For example: Service A handles some data, then it needs to tell Service B to do something with that data. A knows B's endpoint URL and calls it directly.
  2. Using a bus (commonly a Message Queue) to dispatch messages which will be picked up by the single microservices. For example: A will send a message on a common queue, B will receive it and will know what to do.

Both have downsides:

  • Direct-calling other services leads to tight coupling services to other services. If you change service B, you'll likely need to adapt and re-deploy also all other services that interact with B.
  • Using a bus is cool because you don't need to know which service will be able to handle the request, but if the MQ fails for whatever reason it will become the single point of failure of the entire system.

So, what is the preferred way of managing service communications?

Do we have alternatives which can reduce failures and avoid tight-coupling between microservices?

2
  • 1
    If service A or service B is down, this is a single point of failure as well. Obviously introducing more components means allowing higher possibility of failure, though literally the only way to prevent high coupling is the introduction of a third component. The focus should therefore be on making the MQ as robust as possible.
    – Neil
    Sep 20, 2018 at 10:21
  • 1
    The usual counters to "single point of failure" are having "multiple instances of same services, load balanced". The communication pattern is not as much of a concern then.
    – S.D.
    Sep 20, 2018 at 14:16

3 Answers 3

12

As you rightly say, having a component dedicated to pass around messages is definitely better than having every service responsible for knowing how exactly to reach all collaborating services. Therefore, message queues, communication buses etc. are a good idea.

And if they become a single point of failure? Well, you do what you always do for robustness and scaling: you deploy multiple instances of the message queue. If your environment can't keep any of them up, chances are you're not going to get any useful work done anyway. Problem solved.

4
  • When deploying multiple instances of the MQ, the question then becomes, how do you call the MQ from a service when one is down? If you want to make this robust you should have a fallback mechanism in the service itself. Also, the MQ may not be failing, but for example a network connection failed, causing the service not being able to call out. Developers should take care to handle these types of scenarios. Sep 20, 2018 at 9:25
  • you deploy multiple instances of the message queue - Ok but... How does a service know which instance to subscribe to? How does another service know which instance to use when firing messages? Do instances have a centralized storage for messages?
    – BackSlash
    Sep 20, 2018 at 9:41
  • Hopefully you get the opportunity to use a hosted service bus (service bus as a service!) that will have the redundancy built in. In this case the whole message bus will sit behind a loadbalancer or similar to achieve high availability and you don't have to worry about it.
    – Richiban
    Sep 20, 2018 at 10:28
  • I totally agree with what you said, im more knowledgeable in microservices and this can be done by making this service HA. However I'm facing a similar issue but our product this time works with AWS Lambdas and it seems like I'm torn between having a dispatcher/invoker lambda or as the main question said, every lambda alone rather than one lambda to distribute everything. The issue here is I couldn't find any article that talks about making a lambda function robust and highly available
    – Ali_Nass
    Feb 9, 2021 at 15:50
2

Well, let's say service B fails and is not responsive. Now the whole process cannot continue since it still depends on B to do its part of the work. How is B not a single point of failure then?

The advantage I see with having a common bus (or orchestrator, or whatever you have) is the ability to handle single services downtime, e.g. the queue can still keep the messages sent to B until the service is back up and able to consume them.

Also the chances of keeping a single highly available system up are better than having to worry about N different systems with different owners.

Here's an interesting post by Martin Fowler that provides a solution to microservices using events that I think you could use.

1

Whether one topology or the other is best will largely depend on what form your communication takes.

For example, if you're mostly sending through self contained messages that don't require an extensive conversation between services then a brokered message bus works well. This is particularly true if the messages need to reach multiple services or you're agnostic to which service picks up the message. Resilience can be managed with a clustered broker setup that most of the popular message brokers can handle.

If you're communications are mostly two-way, however, peer-to-peer may be the way to go. This would be particularly true if you're streaming data between the services. There are various techniques for mitigating the coupling such as using a discovery service for identifying an appropriate partner. There are also common techniques for limiting interface coupling. For example, having a REST-like API and using an extensible, declarative interface for the business communication. JSON is a popular format, XML was before that etc.

Now that's not to say that you can't perform peer-to-peer through a message bus but you end up managing a lot of session state which can complicate things. If your comms is mostly event with a bit of peer-to-peer it may well still be preferable to do this to keep just one messaging system.

Similarly, if you are mostly streaming with a bit of message passing, you may well embed an event protocol into the streaming protocol for the same reason.

And these aren't your only options. For complex setups, I quite like using ZeroMQ whereby I use one communications "fabric" but apply appropriate topologies where necessary.

In summary, the best messaging topology depends on the nature of the messages. There isn't one correct answer but, on the positive side, it's a well trodden path. You should be able to get good, off-the-shelf, solutions with sensible mitigations unless you're doing something very unusual.

2
  • Interesting. How would you implement peer-to-peer?
    – BackSlash
    Sep 20, 2018 at 10:38
  • @BackSlash Again, depends on what you're doing. If it's fairly standard stuff then I'd go low tech e.g. JSON over HTTP. If you've got some eventing in there then I'd use a request-reply topology in ZeroMQ and pub-sub (or whatever makes sense) for the eventing, For discovery, it depends on how many services you've got. If it's 10's then a config file would be fine. If it's 1000's then an explicit service makes more sense.
    – Alex
    Sep 20, 2018 at 10:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.