← Back to skills
extension
Category: Development & EngineeringAPI key requirement unconfirmed

microservices

Microservices distributed architecture pattern. Use for scalable systems.

personAuthor: jakexiaohubgithub

Microservices

Microservices architecture structures an application as a collection of loosely coupled, independently deployable services. Ideally, each service corresponds to a Bounded Context (DDD).

When to Use

  • Independent Scaling & Deployment: Different business capabilities (e.g. video processing vs user authentication) require independent scaling.
  • Autonomous Multi-Team Velocity: Large engineering organizations where decoupled cross-functional teams need to deploy without stepping on each other.
  • Polyglot Technology Requirements: Leveraging specific runtimes for specific workloads (Python for ML, Go/Rust for networking, Node for APIs).
  • Fault Domain Isolation: Preventing an out-of-memory crash in a non-critical feature from bringing down the core payment pipeline.

Quick Start

# docker-compose.yml (Simulated Microservices)
services:
  order-service:
    build: ./services/order
    ports: ["3001:3000"]
    environment:
      - DB_HOST=order-db

  inventory-service:
    build: ./services/inventory
    ports: ["3002:3000"]

  api-gateway:
    image: nginx
    ports: ["80:80"]
    depends_on:
      - order-service
      - inventory-service

Core Concepts

Database-Per-Service Isolation

Each microservice owns its private database. No service can directly query another service's database tables:

[ Orders Service ] ──→ ( Orders DB )
        │ (Async Events / gRPC)
        ▼
[ Customers Service ] ──→ ( Customers DB )

Distributed Tracing (W3C Trace Context)

Correlates requests across multiple network hops using standardized trace IDs:

// Injected into outgoing HTTP/gRPC calls
headers: {
  "traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}

Circuit Breakers & Graceful Degradation

Fails fast when downstream services become unresponsive, preventing cascading thread exhaustion:

import CircuitBreaker from "opossum";

const breaker = new CircuitBreaker(callRecommendationService, {
  timeout: 1000,
  errorThresholdPercentage: 50,
  resetTimeout: 10000,
});

breaker.fallback(() => [/* Fallback cached generic recommendations */]);
const recommendations = await breaker.fire(userId);

Common Patterns

Circuit Breaker Pattern

Problem: Cascading failures when a downstream dependency experiences degraded response times.
Solution: Wrap external calls in a circuit breaker to fail fast and shed load.

import CircuitBreaker from "opossum";

async function fetchPaymentGateway(payload: PaymentPayload) {
  return await http.post("https://payment.example.com/charge", payload);
}

const breaker = new CircuitBreaker(fetchPaymentGateway, {
  timeout: 3000, // 3s timeout
  errorThresholdPercentage: 50, // Open breaker if 50% calls fail
  resetTimeout: 10000, // Wait 10s before attempting half-open state
});

breaker.fallback(() => ({ status: "QUEUED_FOR_RETRY", cached: true }));
const result = await breaker.fire(paymentData);

Best Practices

Do:

  • Enforce Database-per-Service: Never share a database instance between microservices; communicate via APIs or events.
  • Implement Comprehensive Observability: Instrument all services with OpenTelemetry traces, Prometheus metrics, and structured JSON logs.
  • Use Contract Testing (Pact): Validate API compatibility between consumer and provider services in CI/CD without running end-to-end clusters.
  • Adopt Service Meshes for Mesh Security: Leverage Envoy / Istio for automated mTLS encryption and traffic steering.

Don't:

  • Start with microservices on day one: Start with a well-structured Modular Monolith until organizational scale warrants extraction.
  • Build distributed monoliths: Avoid deep synchronous HTTP chains (Service A calls B, which calls C, which calls D).
  • Ignore distributed transactions: Use Saga patterns or eventual consistency rather than two-phase commits.

Troubleshooting

| Error | Cause | Solution | | :------------------- | :--------------------------------------------- | :--------------------------------------------------------------------- | | Cascading Failure | One service down takes down others. | Use Circuit Breakers and Timeouts. | | Data inconsistency | Async updates failed. | Implement Sagas and Idempotent consumers. | | Latency | Too many hops (service -> service -> service). | Use Caching, Aggregation at Gateway, or Event-Driven data replication. |

References