LFCA 112 ๐ง Microservices โ Concepts
Microservices is an architectural style that structures an application as a collection of small, independently deployable services, each organized around a business capability and communicating through well-defined interfaces. The style emerged as a response to the limitations of monolithic applications: as a monolith grows, its deployment becomes riskier, its scaling becomes coarser, and its codebase becomes harder for multiple teams to work on simultaneously. Microservices address these problems by decomposing the application along boundaries that allow each part to be developed, deployed, and scaled independently.
The term is often used loosely, and the result is that “microservices” sometimes means “distributed monolith” โ a system that has the structure of microservices but the coupling of a monolith. Understanding what microservices actually are, what they require, and what they cost is the difference between an architecture that delivers on its promise and one that adds complexity without benefit. This chapter covers the definition, the characteristics, the decomposition strategies, the communication patterns, and the trade-offs.
Key point: Microservices decompose an application into small, independently deployable services organized around business capabilities. Each service owns its data and communicates through well-defined interfaces, typically over the network. The benefits are independent scaling, deployment, and team autonomy. The costs are distributed systems complexity: network latency, partial failure, and data consistency.
Why microservices exist
The deployment risk problem. In a monolithic application, every change requires redeploying the entire application. A one-line fix in the checkout flow carries the same deployment risk as a major refactor, because both go through the same release process. If the release fails, the entire application is affected. Microservices reduce this risk by limiting the blast radius: a change to one service affects only that service.
The scaling granularity problem. A monolith scales by running more copies of the entire application. If only the search function is under load, the whole application is duplicated. Microservices scale at the service level, so only the service under load is duplicated. This reduces the resource cost of scaling.
The team coordination problem. A single codebase with many contributors requires coordination: merge conflicts, release trains, and shared deployment schedules. A monolith with fifty developers becomes a coordination bottleneck. Microservices give each team its own service, its own codebase, and its own release schedule, which reduces coordination overhead.
The technology lock-in problem. A monolith is written in one language, uses one framework, and stores data in one database. Microservices allow each service to use the technology that fits its problem. A search service might use Elasticsearch; an analytics service might use a columnar database; a real-time service might use a language with strong concurrency primitives.
The fault isolation problem. In a monolith, a memory leak in one component can bring down the entire application. In a microservices architecture, a failure in one service is isolated if the system is designed to tolerate it. The blast radius of a failure is smaller, and the rest of the system continues to function.
a. The definition
Microservices is an architectural style where the application is composed of small services, each running in its own process, communicating through lightweight mechanisms such as HTTP APIs or messaging. Each service is built around a specific business capability and can be deployed independently.
The characteristics that distinguish microservices from other architectures are:
| Characteristic | Meaning |
|---|---|
| Componentization via services | The application is a set of services, not a set of libraries |
| Organized around business capabilities | Services align with business functions, not technical layers |
| Products not projects | Teams own services for their lifetime, not just for a project |
| Smart endpoints, dumb pipes | Business logic lives in services, not in the communication layer |
| Decentralized governance | Each team chooses its own technology |
| Decentralized data management | Each service owns its data |
| Infrastructure automation | Deployment and operations are automated |
| Design for failure | Failure is expected and tolerated |
| Evolutionary design | Services can be replaced and refactored independently |
The last two characteristics โ design for failure and evolutionary design โ are what distinguish a working microservices architecture from a distributed monolith. A distributed monolith has services but no fault isolation and no independent evolution.
b. Decomposition strategies
The first and most important decision is how to decompose the application into services. A poor decomposition produces services that are tightly coupled and must be deployed together, which defeats the purpose. Three strategies are common.
Decompose by business capability. Each service corresponds to a business function: order management, inventory, billing, shipping. This aligns services with the organization’s structure and with the language the business uses. It is the most common and most effective strategy.
Decompose by subdomain (Domain-Driven Design). Each service corresponds to a bounded context in the domain model. The bounded context has its own ubiquitous language, and the boundary is where the model changes meaning. This is a more rigorous version of decomposition by capability.
Decompose by transaction. Each service owns a step in a business transaction. This is sometimes called a saga, and it is used when the transaction spans multiple services. The service that initiates the transaction coordinates the steps.
The anti-pattern is decomposition by technical layer. A “user interface service,” a “business logic service,” and a “data access service” are not microservices; they are layers of a monolith distributed across the network. Each request requires all three services, which means they must be deployed together and cannot scale independently.
c. Communication patterns
Services communicate over the network, and the choice of pattern affects latency, coupling, and failure behavior.
Synchronous communication uses HTTP or gRPC. The caller sends a request and waits for the response. This is simple to understand but creates temporal coupling: if the callee is slow or unavailable, the caller is affected.
Asynchronous communication uses a message broker such as Kafka, RabbitMQ, or NATS. The caller publishes a message and does not wait. The callee consumes the message when it is ready. This decouples the services in time: the caller does not need the callee to be available.
| Aspect | Synchronous | Asynchronous |
|---|---|---|
| Protocol | HTTP, gRPC | Messaging |
| Coupling | Temporal | Decoupled |
| Failure handling | Caller must handle | Broker handles |
| Latency | Immediate | Deferred |
| Complexity | Lower | Higher |
The choice depends on the interaction. A user-facing query is usually synchronous because the user is waiting for the result. An event that triggers a background process is usually asynchronous.
Smart endpoints, dumb pipes is the guiding principle. The business logic lives in the services, not in the communication infrastructure. The pipes โ HTTP, messaging โ are simple and replaceable.
d. Data management
Each microservice owns its data. The service’s database is private; no other service accesses it directly. This is what makes independent deployment possible: the service can change its schema without coordinating with other services.
The consequence is that data consistency across services becomes a distributed systems problem. There is no single transaction that spans multiple services. Instead, the system uses eventual consistency: a change in one service publishes an event, and other services update their data in response.
The saga pattern handles business transactions that span services. A saga is a sequence of local transactions, each in a different service, coordinated by events. If a step fails, the saga executes compensating transactions to undo the previous steps.
The anti-pattern is a shared database. When multiple services read and write the same database, they are coupled at the data layer, and independent deployment becomes impossible. The shared database is the most common cause of a distributed monolith.
e. The costs of microservices
Microservices solve organizational and scaling problems, but they introduce complexity that monoliths do not have. Understanding the costs is essential.
| Cost | Explanation |
|---|---|
| Network latency | Every inter-service call is a network round trip |
| Partial failure | A service can fail while others continue |
| Data consistency | No distributed transactions; eventual consistency |
| Operational complexity | Many services to deploy, monitor, and debug |
| Testing complexity | Integration tests span multiple services |
| Debugging difficulty | A request may traverse many services |
| Infrastructure cost | More compute, more network, more tooling |
The infrastructure cost is not just money. Each service needs a deployment pipeline, a monitoring dashboard, a log stream, and a health check. A system with fifty services needs fifty of each, and the operational overhead grows with the number of services.
f. When microservices are appropriate
Microservices are not a default. They are appropriate when the organization and the application have characteristics that benefit from the decomposition.
| Situation | Recommendation |
|---|---|
| Small team, small application | Monolith |
| Large organization, multiple teams | Microservices |
| Independent scaling needs | Microservices |
| Independent deployment needs | Microservices |
| Technology diversity needs | Microservices |
| Early-stage product, unclear domain | Monolith first |
| Strong consistency requirements | Monolith or modular monolith |
The pragmatic advice is to start with a modular monolith and extract services when the need arises. A modular monolith has clear internal boundaries, so extracting a service later is a matter of moving the module and its data. Premature decomposition produces services that are too small, too coupled, and too numerous to manage.
Complete Example Session
# ============================================
# PART 1: DECOMPOSITION BY BUSINESS CAPABILITY
# ============================================
# Services:
# - orders (order management)
# - inventory (stock levels)
# - billing (payments and invoices)
# - shipping (fulfillment)
# - notifications (email and push)
# ============================================
# PART 2: SERVICE OWNERSHIP
# ============================================
# orders service
# - owns: orders database
# - exposes: POST /orders, GET /orders/:id
# - publishes: order.created, order.cancelled
# ============================================
# PART 3: SYNCHRONOUS COMMUNICATION
# ============================================
# orders service calls inventory service
GET http://inventory-service/api/stock/SKU-123
# Waits for response
# ============================================
# PART 4: ASYNCHRONOUS COMMUNICATION
# ============================================
# orders service publishes an event
topic: order.created
payload: { orderId: '123', items: [...] }
# inventory service consumes it
# ============================================
# PART 5: DATA OWNERSHIP
# ============================================
# Each service has its own database
# orders_db โ owned by orders service
# inventory_db โ owned by inventory service
# billing_db โ owned by billing service
# No shared database
# ============================================
# PART 6: SAGA PATTERN
# ============================================
# Order placement saga:
# 1. orders: create order (pending)
# 2. inventory: reserve stock
# 3. billing: charge payment
# 4. orders: confirm order
# If step 3 fails:
# - inventory: release stock (compensating)
# - orders: cancel order (compensating)
# ============================================
# PART 7: DESIGN FOR FAILURE
# ============================================
# Circuit breaker on the billing call:
# - After N failures, open the circuit
# - Return a fallback response
# - After a timeout, half-open to test
# ============================================
# PART 8: OBSERVABILITY
# ============================================
# - Metrics: request rate, error rate, latency
# - Logs: structured, correlated by trace ID
# - Traces: distributed tracing across services
# ============================================
# PART 9: API GATEWAY
# ============================================
# Single entry point for clients
# Routes to services, handles auth, rate limiting
# /api/orders/* โ orders service
# /api/stock/* โ inventory service
# ============================================
# PART 10: ANTI-PATTERN โ DISTRIBUTED MONOLITH
# ============================================
# Symptoms:
# - Services share a database
# - Services must be deployed together
# - A request requires all services
# - Changes require coordinated releases
These ten parts cover decomposition by business capability, service ownership, synchronous communication, asynchronous communication, data ownership, the saga pattern, designing for failure, observability, the API gateway, and the distributed monolith anti-pattern.
Quick Reference
Characteristics
| Characteristic | Meaning |
|---|---|
| Componentization | Application is a set of services |
| Business capabilities | Aligned with business functions |
| Products not projects | Teams own services long-term |
| Smart endpoints | Logic in services, not pipes |
| Decentralized governance | Each team chooses technology |
| Decentralized data | Each service owns its data |
| Automation | Automated deployment and operations |
| Design for failure | Failure is expected |
| Evolutionary design | Services can be replaced |
Decomposition Strategies
| Strategy | Basis |
|---|---|
| Business capability | Business functions |
| Subdomain (DDD) | Bounded contexts |
| Transaction | Saga steps |
| Technical layer | Anti-pattern |
Communication
| Type | Protocol | Coupling |
|---|---|---|
| Synchronous | HTTP, gRPC | Temporal |
| Asynchronous | Kafka, RabbitMQ | Decoupled |
Data Management
| Aspect | Pattern |
|---|---|
| Ownership | Each service owns its data |
| Consistency | Eventual consistency |
| Transactions | Saga pattern |
| Anti-pattern | Shared database |
Costs
| Cost | Explanation |
|---|---|
| Latency | Network round trips |
| Partial failure | Services fail independently |
| Consistency | No distributed transactions |
| Operations | Many services to manage |
| Testing | Integration across services |
| Debugging | Requests traverse services |
When to Use
| Situation | Recommendation |
|---|---|
| Small team, small app | Monolith |
| Large org, many teams | Microservices |
| Independent scaling | Microservices |
| Early-stage product | Monolith first |
| Strong consistency | Monolith or modular monolith |
Best Practices
โ Do This:
# Decompose by business capability
services:
- orders
- inventory
- billing
# Each service owns its data
orders_db:
owner: orders-service
# Use asynchronous events for background work
topic: order.created
# Design for failure
circuitBreaker:
failureThreshold: 5
timeout: 30000
# Expose health checks
livenessProbe:
httpGet:
path: /healthz
โ Don’t Do This:
# Share a database between services
shared_db: # โ couples services at the data layer
# Decompose by technical layer
ui_service: # โ
logic_service: # โ distributed monolith
data_service: # โ
# Require all services for a single request
# โ defeats independent deployment
# Deploy services together
# โ they are not independent
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Distributed monolith | Shared database, coupled deployment | Enforce data ownership |
| Too many services | Premature decomposition | Start with a modular monolith |
| Too few services | One service per team, not per capability | Decompose by capability |
| Chatty services | Fine-grained calls | Coarser interfaces, batching |
| No fault isolation | Synchronous chains | Circuit breakers, timeouts |
| No observability | Distributed systems are opaque | Metrics, logs, traces |
| Shared libraries | Coupling through code | Keep services independent |
Real-World Examples
1. Order Service
service: orders
database: orders_db
endpoints:
- POST /orders
- GET /orders/:id
events:
- order.created
- order.cancelled
2. Inventory Service
service: inventory
database: inventory_db
endpoints:
- GET /stock/:sku
- POST /reserve
events:
- stock.reserved
- stock.released
3. Saga for Order Placement
steps:
- create_order
- reserve_stock
- charge_payment
- confirm_order
compensations:
- release_stock
- cancel_order
4. Circuit Breaker
circuitBreaker:
failureThreshold: 5
resetTimeout: 30000
5. Event Publishing
topic: order.created
payload:
orderId: '123'
customerId: '456'
6. API Gateway
routes:
- path: /api/orders/*
service: orders
- path: /api/stock/*
service: inventory
7. Health Check
livenessProbe:
httpGet:
path: /healthz
port: 8080
8. Distributed Tracing
traceId: abc-123
spans:
- orders-service
- inventory-service
- billing-service
9. Service Mesh
# Sidecar proxy handles mTLS, retries, circuit breaking
10. Shared Library (Anti-pattern)
# Domain models shared across services
# โ use events and APIs instead
Visual
Microservices vs Monolith
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MONOLITH: โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Single deployable unit โ โ
โ โ โโโ UI โ โ
โ โ โโโ Orders โ โ
โ โ โโโ Inventory โ โ
โ โ โโโ Billing โ โ
โ โ One database โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ MICROSERVICES: โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ Orders โ โInventoryโ โ Billing โ โ
โ โ DB โ โ DB โ โ DB โ โ
โ โโโโโโฌโโโโโ โโโโโโฌโโโโโ โโโโโโฌโโโโโ โ
โ โ โ โ โ
โ โโโโโโโโโโโโโโผโโโโโโโโโโโโโ โ
โ โ โ
โ API Gateway โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Communication Patterns
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SYNCHRONOUS: โ
โ Client โโHTTPโโโถ Service A โโHTTPโโโถ Service B โ
โ โโโ Caller waits for the response โ
โ โ
โ ASYNCHRONOUS: โ
โ Service A โโpublishโโโถ Message Broker โโconsumeโโโถ Service Bโ
โ โโโ Caller does not wait โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Saga Pattern
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Order placement saga: โ
โ โ
โ 1. orders: create order (pending) โ
โ 2. inventory: reserve stock โ
โ 3. billing: charge payment โ fails โ
โ 4. inventory: release stock (compensating) โ
โ 5. orders: cancel order (compensating) โ
โ โ
โ Each step is a local transaction. โ
โ Compensating transactions undo the previous steps. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Data Ownership
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CORRECT: โ
โ orders_db โ only orders service โ
โ inventory_db โ only inventory service โ
โ billing_db โ only billing service โ
โ โ
โ ANTI-PATTERN: โ
โ shared_db โ all services read and write โ
โ โโโ couples services, prevents independent deployment โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Definition | Small, independently deployable services |
| Organization | By business capability |
| Communication | HTTP, gRPC, or messaging |
| Data | Each service owns its data |
| Consistency | Eventual consistency |
| Transactions | Saga pattern |
| Failure | Design for failure |
| Benefits | Independent scaling, deployment, team autonomy |
| Costs | Latency, partial failure, operational complexity |
| Anti-pattern | Distributed monolith, shared database |
| Recommendation | Start with a modular monolith |
Key takeaways:
- Microservices decompose an application into small, independently deployable services. Each service is organized around a business capability and communicates through well-defined interfaces.
- The defining characteristics are independent deployment and data ownership. A service can be changed and deployed without coordinating with other services, and each service owns its data. Without these, the architecture is a distributed monolith.
- Decompose by business capability, not by technical layer. A “UI service” and a “logic service” are layers of a monolith distributed across the network. A “order service” and an “inventory service” are capabilities that can evolve independently.
- Communication is synchronous or asynchronous. Synchronous calls are simpler but create temporal coupling. Asynchronous messaging decouples the services in time but adds complexity.
- Data consistency becomes a distributed systems problem. There are no distributed transactions. The system uses eventual consistency and the saga pattern to maintain consistency across services.
- The costs are real. Network latency, partial failure, operational complexity, testing complexity, and debugging difficulty all increase. The benefits must outweigh these costs.
- Start with a modular monolith. Decompose into services when the need arises. A modular monolith has clear boundaries, so extracting a service later is a matter of moving the module and its data.
Remember: Microservices is an architectural style that solves organizational and scaling problems, not a default. It decomposes an application into small services that can be developed, deployed, and scaled independently, with each service owning its data and communicating through well-defined interfaces. The benefits are real: independent scaling, independent deployment, team autonomy, and fault isolation. The costs are also real: network latency, partial failure, data consistency challenges, and operational complexity. The decision to adopt microservices should be driven by the needs of the organization and the application, not by the popularity of the term. Start with a modular monolith, extract services when the boundaries are clear and the need is real, and avoid the distributed monolith that has the structure of microservices without the benefits.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!