System ArchitectureSystem Architect

How to properly organize interaction between microservices to minimize coupling (loose coupling) and maximize scalability?

Pass interviews with Hintsage AI assistant

Answer.

Minimizing coupling (loose coupling) between microservices is one of the key principles of modern architecture. This is achieved through asynchronous interaction (via message queues or event buses), avoiding direct synchronous HTTP calls when not necessary, and defining explicit API contracts.

A popular approach is to use message brokers (RabbitMQ, Kafka, NATS), where microservices publish events about their state, and subscribers react to them.

Example of publishing and processing an event in Kafka using Node.js:

// producer.js const { Kafka } = require('kafkajs') const kafka = new Kafka({ clientId: 'order-service', brokers: ['kafka01:9092'] }) const producer = kafka.producer() await producer.connect() await producer.send({ topic: 'orders', messages: [ { value: JSON.stringify({orderId: 123}) } ] }) await producer.disconnect() // consumer.js const consumer = kafka.consumer({ groupId: 'payment-group' }) await consumer.connect() await consumer.subscribe({ topic: 'orders', fromBeginning: true }) await consumer.run({ eachMessage: async ({ topic, partition, message }) => { const order = JSON.parse(message.value.toString()) // process the order }})

Key features:

  • Microservices communicate through a formalized API or intermediary (queue, bus)
  • Each service has its own database (Database per Service) to avoid locks and competition
  • New services can be added on the fly without changing existing ones

Trick Questions.

Question: Is it permissible to use a shared database for multiple microservices if this is one large project?

No, this violates the principle of independence, leads to tight coupling, and worsens scalability and maintainability. Separate databases or schemas must be used.

Question: Is synchronous HTTP interaction between services an acceptable practice when scaling the system?

Synchronous HTTP requests scale poorly and can become a bottleneck. Asynchronous mechanisms should be implemented, and synchronous calls should only be used in cases of absolute necessity.

Question: Can a microservice be scaled only by the number of its instances without changing the system architecture?

No, simply increasing the number of instances does not solve the problems of coupling or bottlenecks in architecture. An analysis of bottlenecks, implementation of queues, caching, and service responsibility separation is necessary.