Micro-services architecture loose coupling complications
Asked Answered
O

1

6

I'm fairly new to the whole micro-services bandwagon. I have been doing some research into the architecture and principles behind a good micro-services environment.

One of the main things that defines a micro-service is supposed to be the loosely coupled nature of each service. Micro Service A should never call Micro Service B directly, or you're effectively creating a monolithic system that looses the scalability offered by the architecture pattern.

Question / example

If I develop a micro-service that returns a GUID (for example), it's reasonable to suggest that other micro-services in the environment might call the GUID service directly when one is required.

I understand that a variety of queuing systems can be used to pass data from one service to the next, but in my mind they're for inserting, deleting or updating primarily.

I can't get my head round how a queue would be used for a simple read (like my GUID example) and why you wouldn't just call the GUID service directly from another micro-service.

Note: Returning a GUID is just an example, I'm aware most languages are able to generate them internally

Some clarity on this would be much appreciated.

Oath answered 18/6, 2019 at 12:30 Comment(3)
You are thinking about it all wrong. Queues are used for transmitting events. Events describe things which have already happened. Get me a GUID is a command, which is an instruction for something to happen in the future. In a microservices architecture, event messages can be used to synchronise state between individual services. Rather than a GUID in your example. imagine a User. When a user is created, a UserCreated event is published by the Users service. This allows any other service to consume that data too. So no call to the Users service is necessary to get the user any more.Anticathexis
Also, it does not break any rules to have microservices call each other directly over http(s). Any system design which mandated that you should never do this is wrong. Microservice architecture seeks to reduce coupling, not eliminate it. Direct calls are sometimes the best, or even the only, way to transfer state between services. It's just that most of the time, the cost in terms of increased coupling is not worth the benefits.Anticathexis
Thanks for your response @tomredfern, that makes things a bit clearer. Some more research on the event messages aspect required I think.Oath
I
8

You should not follow every rule as it is.

There are many exceptions to this rule and the practices of lot of systems has proven it not to be correct for every case or system.

I disagree with this restriction that micro-service A should never call micro-service B as a general rule as it does not apply to all cases. I have worked with multiple systems using micro-services and we where not following that.

Communication between micro-services:

You can use multiple ways to communicate between micro-services like:

  1. Events (using queue)

  2. Commands - direct call over API to another micro-service (which is some kind of instruction to the micro-service) which requires a change to happen(Create, Update, Delete).

  3. Queries - direct call over API to another micro-service (like your example of getting GUID). Again some people will say that this is a Command as well. Using Query as term is often combined while you use CQRS as well.

  4. Shared Db's (most of the online resources will tell you not to do this for multiple reasons) In general this is not recommended approach.

In general

You should work with your system based on your needs and not based on set in stone rules like "Micro Service A should never call Micro Service B".

I will give you an example why:

Example:

Lets say you have "micro-service A" and "micro-service B". Your "micro-service B" is consuming events which "micro-service A" publishes through Kafka. "Micro-service B" when consuming the events is storing some relevant "External" data in its own database(duplicating it). This is common approach not to call the "micro-service A" each time you need some of its data. This is common for example if "micro-service A" is some service having the system configuration settings or similar.

Lets say you have scenario of disaster where your database and all the data from your "micro-service B" is destroyed or corrupted. In order to solve the problem you could just restore your backup and apply the apply latest events from lets say last 1h where your "micro-service B" was down and solve the problem(If your event handling is implemented to be Idempotent). All good in this case.

On the other hand if you have a system running for a while on production. After some point you develop "micro-service C" and decide to deploy it to production. It turns out that you need some data that "micro-service A" produces. You need that data on your "micro-service C" as External data similar as you had it with "micro-service B". How do you get that data? You consume all the events from "micro-service A"? In ideal world you would keep all the events in Kafka forever. In this case you would just subscribe for events and apply all of them to save all the data you need in "micro-service C". In reality you need to set some Retention Period to your Kafka for lets say 5 days. If you have a system running longer then 5 days you can not recreate your data from events.

In this case you need to call the service directly with Command/Query and populate the "micro-service C" database.

This is just one edge case example for which you will need to have a direct call.

Summary:

There are many other examples where this approach is valid as well. Very often you will for example need to call another micro-service synchronously and you will want to wait for the response(depending of your business scenario). The best way to do this is calling another micro-service directly with a Command/Query.

Interlope answered 18/6, 2019 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.