Decoupling Microservices: Asynchronous Messaging, Event‑Driven Architecture, and CQRS Strategies
The article examines how to reduce tight coupling between microservices by applying module‑division principles, converting synchronous calls to asynchronous messaging, leveraging event‑driven architectures and CQRS, employing local caching and data landing, and refactoring overly coupled services for more resilient backend systems.
Today we discuss how to decouple microservices and refactor tightly coupled services, building on previous articles about reasonable microservice module sizing and granularity.
Principle 1: Keep fewer than 10 microservice modules.
Principle 2: Do not split modules with strong data relationships.
Principle 3: Let data aggregation drive business function aggregation.
Principle 4: Shift from vertical functional division to horizontal layered thinking.
Principle 5: Maintain high cohesion and loose coupling.
Problem Overview
Microservice adoption introduces distributed transactions and cross‑service API calls, increasing system complexity and creating avalanche effects when a single service fails.
Enterprises often lack the operational maturity to handle these challenges, leading to performance, monitoring, and fault‑analysis gaps.
Convert Synchronous Calls to Asynchronous Calls
Message middleware (e.g., RabbitMQ, Kafka, WebLogic JMS) enables asynchronous communication, providing time, space, and flow decoupling.
Message middleware characteristics:
Time decoupling – producers and consumers need not be online simultaneously.
Space decoupling – endpoints do not need to know each other's physical addresses.
Flow decoupling – communication does not block processing flows.
Typical middleware protocols:
AMQP‑based (RabbitMQ, Kafka)
JMS‑based (WebLogic JMS, IBM MQ)
Common use cases include notification, asynchronous integration, peak‑shaving, publish/subscribe, and high‑reliability scenarios.
Event‑Driven Architecture (EDA) Core Business Analysis
EDA shifts analysis from process‑driven to event‑driven, identifying business events, their triggers, and state changes.
In EDA, events flow between loosely coupled components; an event manager retains events for unavailable consumers and retries later.
EDA characteristics:
Broadcast communication
Real‑time event delivery
Asynchronous processing
Fine‑grained, value‑driven events
Complex event processing and aggregation
Parallel execution and non‑blocking behavior
From Synchronous Interfaces to Local Message Cache
When a synchronous call fails, store the message locally and retry via scheduled tasks, separating validation from actual transmission.
Local Cache or Data Landing for Query Services
memcached is a distributed cache that uses CRC‑32 for key hashing and LRU for eviction.
Cache frequently accessed reference data locally to reduce dependency on upstream services; consider API‑gateway or ESB caching for repeated calls.
Refactoring Existing Tight Coupling
If two services heavily call each other (e.g., >30% cross‑table access), merge them or extract common functionality into a shared service.
Move fine‑grained services to coarser‑grained domain services to avoid exposing CRUD‑style interfaces.
Applying CQRS
CQRS separates command (CUD) handling from query (R) handling, using events to propagate state changes to read models.
It aligns well with event‑driven messaging and can leverage both relational and NoSQL read stores for scalability.
While CQRS improves modularity, it introduces eventual consistency and requires reliable event delivery.
Overall, decoupling microservices through asynchronous messaging, event‑driven design, local caching, and careful service granularity leads to more resilient, scalable backend systems.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.