Shikhil Saxena

Jan 23, 2026 • 8 min read

Microservices Are Killing Your Performance (And Here's the Math)

The promise: Microservices make your system scalable, maintainable, and fast.

The reality: For most systems, microservices add latency, complexity, and failure points without meaningful benefits.

Let's look at the actual numbers.


The Performance Cost of Network Calls

The fundamental problem: Microservices communicate over the network. Networks are slow.

Latency Comparison

In-process function call (monolith):

Function call: 0.001ms (1 microsecond)

HTTP call within same datacenter (microservices):

HTTP request: 1-5ms (1,000-5,000 microseconds)

That's 1,000x-5,000x slower.

Real-World Example

Scenario: E-commerce checkout flow

Operations needed:

  1. Validate user session

  2. Check product inventory

  3. Calculate shipping cost

  4. Process payment

  5. Create order record

  6. Send confirmation email

Monolith architecture:

Total time: 6 function calls × 0.001ms = 0.006ms
Database queries: 3 × 2ms = 6ms
External API (payment): 150ms
Total: ~156ms

Microservices architecture:

Service calls:
- User service: 2ms
- Inventory service: 3ms 
- Shipping service: 2ms
- Payment service: 2ms + 150ms (external API)
- Order service: 3ms
- Notification service: 2ms

Each call includes:
- Serialization/deserialization: 0.5ms
- Network latency: 1-2ms
- Service processing: 1-2ms

Total service overhead: 6 services × 3ms = 18ms
Database queries: 6 services × 1 query × 2ms = 12ms
External API: 150ms
Total: ~180ms

Result: Microservices are 15% slower for this simple flow.


The N+1 Service Problem

In databases, we know about N+1 queries. Microservices have N+1 services.

Example: Display User Dashboard

Requirements:

  • Show user profile

  • Show last 10 orders

  • Show recommendations based on order history

Monolith (optimized):

-- Single query with JOIN
SELECT 
 users.*,
 orders.*,
 recommendations.*
FROM users
LEFT JOIN orders ON orders.user_id = users.id
LEFT JOIN recommendations ON recommendations.user_id = users.id
WHERE users.id = $1
LIMIT 10;

Execution time: ~5ms

Microservices (realistic):

// 1. Get user
const user = await userService.getUser(userId); // 3ms

// 2. Get orders (requires user_id from step 1)
const orders = await orderService.getOrders(userId); // 3ms

// 3. Get recommendations (requires orders from step 2)
const orderIds = orders.map(o => o.id);
const recommendations = await recommendationService
 .getByOrders(orderIds); // 3ms

// Total: 9ms (sequential)
// Can't parallelize due to data dependencies

Execution time: ~9ms (80% slower)

And this assumes:

  • Perfect network conditions

  • No service failures

  • No retry logic

  • No circuit breakers


The Hidden Costs: Real Benchmarks

Let's measure actual overhead with a controlled experiment.

Test Setup

System: Simple CRUD application

  • 4 entities: Users, Products, Orders, Payments

  • 10,000 requests/sec load

  • AWS EC2 t3.medium instances

Architecture 1: Monolith

┌─────────────────┐
│ Application │
│ (Node.js) │
│ │
│ ┌───────────┐ │
│ │ Database │ │
│ │ (Postgres)│ │
│ └───────────┘ │
└─────────────────┘

Configuration:

  • Single Node.js process

  • Connection pooling (20 connections)

  • Redis cache (same instance)

Architecture 2: Microservices

┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ User │ │ Product │ │ Order │ │ Payment │
│ Service │ │ Service │ │ Service │ │ Service │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
 │ │ │ │
 └─────────────┴─────────────┴─────────────┘
 │
 ┌──────┴──────┐
 │ Postgres │
 │ (shared) │
 └─────────────┘

Configuration:

  • 4 Node.js services

  • Service mesh (Istio)

  • Same Postgres database

  • Redis cache (shared)

Benchmark Results

MetricMonolithMicroservicesDifferencep50 latency12ms18ms+50%p95 latency25ms45ms+80%p99 latency50ms120ms+140%Throughput10,000 req/s8,500 req/s-15%CPU usage45%65%+44%Memory usage512MB2GB+300%Network I/O50 MB/s180 MB/s+260%

Key findings:

  1. Tail latency suffers most (p99: +140%)

  2. Resource usage increases dramatically

  3. Throughput decreases despite "scalability"


Network Overhead Breakdown

Let's dissect where time is spent in a microservice call.

Anatomy of a Service-to-Service Call

Total time: ~3ms

DNS resolution: 0.1ms (cached)
TCP handshake: 0.5ms (within datacenter)
TLS handshake: 1.0ms (if using HTTPS)
HTTP headers: 0.2ms
Request serialization: 0.3ms (JSON)
Network transmission: 0.5ms
Service processing: 0.5ms
Response serialization: 0.3ms
Network transmission: 0.5ms
Response parsing: 0.2ms
────────────────────────────
Total: ~3.0ms

In a monolith:

Function call: 0.001ms
────────────────────────
Total: 0.001ms

That's 3,000x overhead for the same operation.


The Cascading Failure Problem

Microservices amplify failure rates.

Failure Math

Assumptions:

  • Each service has 99.9% uptime (3 nines - pretty good!)

  • Request requires 5 services

Monolith:

Availability: 99.9%
Downtime: 43 minutes/month

Microservices (5 services in chain):

Availability: 0.999^5 = 0.995 = 99.5%
Downtime: 3.6 hours/month

That's 5x more downtime.

Real-World Cascade

User Request
 ↓
API Gateway (99.9%)
 ↓
Auth Service (99.9%)
 ↓
Product Service (99.9%)
 ↓
Inventory Service (99.9%)
 ↓
Price Service (99.9%)
 ↓
Response

Combined availability: 99.5%

Add:

  • Circuit breakers (add latency)

  • Retries (3x network calls on failure)

  • Fallbacks (partial degradation)

Result: Complex, slow, still fails more often.


Database Contention

Microservices don't solve database bottlenecks - they make them worse.

The Problem

Monolith:

Application → Connection Pool (20) → Database

Microservices:

User Service → Pool (20) ───┐
Product Service → Pool (20) ├→ Database (max 100 connections)
Order Service → Pool (20) ──┤
Payment Service → Pool (20) ┘

Total connections: 80 (near database limit)

Issues:

  1. Connection exhaustion faster

  2. Lock contention increases (more concurrent transactions)

  3. Query cache less effective (different access patterns per service)

Performance Impact

Test: 1,000 concurrent users

ArchitectureConnections UsedLock Wait TimeQuery TimeMonolith20-305ms10msMicroservices60-8025ms18ms

Microservices use 3x connections and have 5x lock contention.


Serialization Overhead

Every network call requires serialization/deserialization.

JSON Serialization Cost

Test: Serialize typical API response (user object with nested data)

const user = {
 id: 123,
 name: "John Doe",
 email: "[email protected]",
 profile: { /* 50 fields */ },
 orders: [ /* 10 orders */ ]
};

Benchmarks (Node.js):

OperationTimeIn-memory object access0.001msJSON.stringify()0.15msJSON.parse()0.20msNetwork transmission0.50msTotal per call0.85ms

In a microservices chain with 6 services:

Total serialization overhead: 6 × 0.85ms = 5.1ms

That's 5ms spent just converting data to/from JSON.


When Microservices Actually Make Sense

I'm not saying "never use microservices."

Use microservices when:

1. Independent Scaling Requirements

Example: Video streaming platform

Video Upload Service: CPU-intensive (encoding)
 → Needs: 8 CPU cores, 4GB RAM
 → Scale: 5 instances

Metadata Service: Memory-intensive (search)
 → Needs: 2 CPU cores, 16GB RAM
 → Scale: 3 instances

Video Playback Service: I/O-intensive (CDN)
 → Needs: 1 CPU core, 2GB RAM
 → Scale: 20 instances

Each service has different resource needs. Monolith wastes resources.

2. Team Boundaries

Example: Company with 100+ engineers

Team A: User Management (15 engineers)
Team B: Payment Processing (10 engineers)
Team C: Inventory (12 engineers)
Team D: Recommendations (8 engineers)

Monolith:

  • 100 engineers touching same codebase

  • Merge conflicts daily

  • Deploy coordination nightmare

Microservices:

  • Teams deploy independently

  • Clear ownership boundaries

  • Faster iteration

Threshold: 50+ engineers working on same product.

3. Technology Diversity

Example: ML-heavy application

Web API: Node.js (familiar to web team)
ML Model Serving: Python (scikit-learn, TensorFlow)
Real-time Analytics: Go (performance)
Data Processing: Rust (memory safety)

Monolith: Can't mix languages easily.

Microservices: Each service uses best tool for the job.

4. Compliance Requirements

Example: Healthcare application

PHI (Protected Health Information):
 → Strict audit logs
 → Encrypted at rest
 → Access controls
 → Isolated database

Non-PHI (Billing, Marketing):
 → Normal security
 → Shared database

Separate services simplify compliance scope.


The Modular Monolith Alternative

Best of both worlds: monolith structure with microservices discipline.

Architecture

┌─────────────────────────────────────┐
│ Application (Monolith) │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ User │ │ Product │ │
│ │ Module │ │ Module │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ┌────┴────────────┴────┐ │
│ │ Shared Database │ │
│ └─────────────────────┘ │
└─────────────────────────────────────┘

Key principles:

  1. Modules communicate via interfaces (not HTTP)

  2. Clear boundaries (like microservices)

  3. Shared database (transaction benefits)

  4. Single deployment (no network overhead)

Performance Comparison

MetricMicroservicesModular MonolithImprovementLatency (p50)18ms12ms33% fasterLatency (p99)120ms50ms58% fasterThroughput8,500 req/s10,000 req/s18% higherMemory2GB512MB75% lessComplexityHighMediumSimpler

Benefits:

✅ Fast (no network calls)

✅ Modular (clear boundaries)

✅ Transactional (ACID guarantees)

✅ Debuggable (single stack trace)

✅ Testable (no mocking services)

Trade-offs:

⚠️ Single deployment (can't scale modules independently)

⚠️ Single language (usually)

⚠️ Shared database (schema coordination needed)


The Migration Path

Don't rewrite monolith → microservices overnight.

Phase 1: Identify Candidates (Month 1)

Criteria:

  • Independent scaling needs

  • Different technology requirements

  • Team boundaries

  • Compliance isolation

Example:

Keep in monolith:
- User management
- Product catalog
- Order processing

Extract to services:
- Video encoding (CPU-intensive)
- Email sending (I/O-intensive)
- ML recommendations (Python-specific)

Phase 2: Extract One Service (Month 2-3)

Start with lowest-risk service:

Before:
┌─────────────────┐
│ Monolith │
│ - Users │
│ - Products │
│ - Email │ ← Extract this
└─────────────────┘

After:
┌─────────────────┐ ┌─────────────┐
│ Monolith │────→│ Email │
│ - Users │ │ Service │
│ - Products │ └─────────────┘
└─────────────────┘

Measure:

  • Latency impact

  • Error rate changes

  • Operational complexity

If benefits < costs: Stop here.

Phase 3: Gradual Extraction (Month 4-6)

Extract 1 service per month:

  • Monitor performance

  • Measure operational overhead

  • Validate benefits

Stop when:

  • Complexity outweighs benefits

  • Team can't manage more services

  • Performance degrades


Cost Analysis: Real Numbers

Scenario: 10,000 requests/second application

Monolith Infrastructure

Application:
- 3x t3.large instances (4 CPU, 8GB) @ $0.0832/hr
 = $180/month

Database:
- 1x db.r5.xlarge (4 vCPU, 32GB) @ $0.29/hr
 = $210/month

Load Balancer:
- 1x ALB @ $20/month
 = $20/month

Total: $410/month

Microservices Infrastructure

Services (4 services × 3 instances):
- 12x t3.medium instances (2 CPU, 4GB) @ $0.0416/hr
 = $360/month

Service Mesh:
- 12x sidecar proxies (overhead)
 = +30% CPU = $108/month

Database:
- 1x db.r5.2xlarge (8 vCPU, 64GB) @ $0.58/hr
 (needs more capacity for connection overhead)
 = $420/month

Load Balancers:
- 1x ALB (external) @ $20/month
- 1x NLB (internal) @ $25/month
 = $45/month

Service Discovery:
- Consul cluster (3 nodes) @ $30/month
 = $30/month

Monitoring (per-service):
- Datadog/New Relic @ $100/month
 = $100/month

Total: $1,063/month

Microservices cost 2.6x more for the same workload.


Debugging & Observability

Monolith: Single Stack Trace

Error: Payment failed
 at processPayment (payment.js:42)
 at createOrder (order.js:18)
 at handleCheckout (checkout.js:5)
 at Router.post (/api/checkout)

Debug time: 5 minutes (follow stack trace)

Microservices: Distributed Tracing Required

Error: Payment failed

Service: order-service
Trace ID: abc123
Span: checkout

↓ HTTP call (2ms)

Service: payment-service 
Trace ID: abc123
Span: process_payment
 ↓ HTTP call (150ms)

Service: stripe-gateway
Trace ID: abc123
Error: Card declined

Total trace spans: 15
Services involved: 4
Debug time: 30 minutes (correlate logs across services)

Additional tools needed:

  • Distributed tracing (Jaeger, Zipkin)

  • Log aggregation (ELK, Loki)

  • Service mesh observability (Istio, Linkerd)

Cost: $200-500/month for observability stack


Decision Matrix

Should you use microservices?

Do you have 50+ engineers? 
├─ No → Monolith
└─ Yes
 ├─ Do services need independent scaling?
 │ ├─ No → Modular Monolith
 │ └─ Yes
 │ ├─ Can you afford 2-3x infrastructure cost?
 │ │ ├─ No → Monolith
 │ │ └─ Yes
 │ │ ├─ Can you afford performance degradation?
 │ │ │ ├─ No → Monolith
 │ │ │ └─ Yes → Microservices ✅

For 90% of applications: Monolith or Modular Monolith


The Real Problem Microservices Solve

Microservices don't solve technical problems.

They solve organizational problems:

✅ Team autonomy

✅ Independent deployment

✅ Clear ownership

✅ Technology diversity

If you don't have these organizational problems, you don't need microservices.


Conclusion: The Performance Paradox

Microservices promise:

  • Scalability

  • Resilience

  • Performance

Microservices deliver:

  • Higher latency (+50-150%)

  • More failures (5x downtime)

  • More complexity (10x operational overhead)

But also:

  • Team independence

  • Faster iteration (for large teams)

  • Technology flexibility

The trade-off is real. Choose consciously.


Resources

Books:

  • "Building Microservices" by Sam Newman

  • "Monolith to Microservices" by Sam Newman (yes, same author, both sides)

Tools for Monoliths:

  • Module boundaries: NX, Turborepo

  • Testing: Jest, Playwright

  • Deployment: Docker, single container

Tools for Microservices:

  • Service mesh: Istio, Linkerd

  • Tracing: Jaeger, Zipkin, Honeycomb

  • Service discovery: Consul, Eureka

Benchmarking:


TL;DR

Microservices add:

  • +50-150% latency (network overhead)

  • +300% resource usage (multiple instances)

  • +500% operational complexity (distributed systems)

  • 2-3x infrastructure costs

Use microservices when:

  • 50+ engineers on same product

  • Independent scaling requirements

  • Technology diversity needed

  • Compliance isolation required

Otherwise: Use a modular monolith.


What's your experience with microservices vs monoliths? Share your performance numbers in the comments! 👇

P.S. - If you want a follow-up on "Modular Monolith Architecture" or "Microservices Migration Horror Stories", let me know!

Join Shikhil on Peerlist!

Join amazing folks like Shikhil and thousands of other builders on Peerlist.

peerlist.io/

It’s available... this username is available! 😃

Claim your username before it's too late!

This username is already taken, you’re a little late.😐

1

7

0