Beginner

Microservices Foundations

What microservices are, why and when to use them, communication patterns and how to adopt them.

Level: Beginner to Intermediate


Table of Contents

  1. Module 1 — What Are Microservices?
  2. Module 2 — Why Microservices?
  3. Module 3 — Communication Patterns
  4. Module 4 — Adopting Microservices
  5. Architecture Diagrams
  6. Reference Tables

Module 1 — What Are Microservices?

Microservices vs Monoliths

When developing software, it starts small — a few features. But as features are added, complexity accumulates. When all this complexity stays in the same program, it’s called a monolithic architecture — a monolith.

A monolith is not necessarily bad. A well-maintained monolith often has a modular architecture with abstractions that facilitate maintainability. But everything lives in the same application.

Microservices work differently: it’s a collection of independent programs that collaborate to solve business problems, rather than having all business logic in the same program.

graph TB
    subgraph Monolith["Monolithic Architecture"]
        M[Single Application]
        M --> F1[Feature: Users]
        M --> F2[Feature: Orders]
        M --> F3[Feature: Payments]
        M --> F4[Feature: Notifications]
        M --> F5[Feature: Analytics]
    end

    subgraph Micro["Microservices Architecture"]
        GW[API Gateway]
        GW --> S1[Users Service]
        GW --> S2[Orders Service]
        GW --> S3[Payments Service]
        GW --> S4[Notifications Service]
        GW --> S5[Analytics Service]
        S1 --- DB1[(Users DB)]
        S2 --- DB2[(Orders DB)]
        S3 --- DB3[(Payments DB)]
    end

Microservices Characteristics

1. Collection of Small, Independent Services

The “micro” in microservices means small. Each service should be relatively simple to understand in its entirety, which simplifies maintenance and promotes flexibility.

2. Heterogeneous Technology Stacks

It is common for different services to use different programming languages, frameworks, and data storage technologies. This allows selecting best-of-breed solutions, experimenting with new technologies, and making stack changes with little friction.

3. Independent Development and Deployment

Each service can be redeployed without affecting others. In monolithic architectures, deployment is often all-or-nothing. This independence allows separate teams to deliver business value autonomously, without waiting for synchronization with other teams.

4. Communication Over the Network

Microservices communicate with each other via the network. Network latency is much greater than API calls within the same process — a structural constraint that reinforces separation of concerns and cohesion:

  • Tightly coupled elements should be in the same microservice
  • Loosely coupled elements can be in separate microservices

5. Domain-Driven Design (DDD)

The most effective approach to delimiting microservice boundaries involves applying Domain-Driven Design principles, based on:

  • Bounded Context — contextual boundary of a business domain
  • Ubiquitous Language — vocabulary shared between developers and business experts

The Microservices Ecosystem

Infrastructure and Containerization

TechnologyCategoryExamples
ContainerizationRuntimeDocker, Podman
Container OrchestrationPlatformKubernetes, Helm
Cloud-Managed ContainersCloudAWS Elastic Beanstalk, GCP Cloud Run, Azure Container Apps
Event BrokersMessagingApache Kafka, RabbitMQ, AWS SQS/SNS, GCP Pub/Sub, Azure Service Bus
Serverless FunctionsComputeAWS Lambda, GCP Cloud Run Functions, Azure Functions

Organization and DevOps Practices

Microservices teams rely heavily on:

  • Test Automation and Continuous Integration (CI)
  • Continuous Deployment/Delivery (CD)
  • Infrastructure as Code (IaC)
  • DevOps practices: cross-functional teams, fast feedback, experimentation
  • Site Reliability Engineering (SRE)

Module 2 — Why Microservices?

Microservices benefits fall into three main categories: Complexity, Scale, and Governance.

Throughout the course, these concepts are illustrated by Globomantics, a fictional social networking company with millions of global users.

Managing Complexity

Globomantics manages many distinct business complexities:

  • Feed algorithm — Graph analysis to determine what content to show which user
  • Content moderation — Hybrid moderation (community + ML) to detect harmful content
  • Ad targeting — Machine learning to build an advertising profile per user
  • Advertiser portal — Distinct interface for advertisers

With a monolithic architecture, all these complexities coexist in the same codebase, creating:

  • Entanglement between unrelated domains
  • Difficulty deploying isolated changes
  • Risk that a bug in one feature impacts the entire system

With microservices, each complexity domain can be isolated in its own service, with its own team, deployment cycle, and adapted technology stack.

Microservices and Scale

Scale Challenges at Globomantics

MetricEstimate
Total users1,000,000
Simultaneous active users (5%)50,000
Requests/sec (0.1 req/user/sec)5,000 req/s
Load spikesUp to 100,000+ req/s

Types of Workloads to Scale Differently

  • Feed generation — Compute-intensive, requires lots of CPU and RAM
  • Image/Video processing — Storage, content scanning, global serving with access rules
  • Notifications — Very high volume of push messages
  • ML ad profiles — Continuous profile updates by ML models

The key advantage: with microservices, you can scale each service independently according to its specific needs, rather than scaling the entire monolithic application.

graph LR
    Users[Users] --> LB[Load Balancer]
    LB --> FeedSvc[Feed Service\nx10 instances]
    LB --> ImgSvc[Image Service\nx5 instances]
    LB --> NotifSvc[Notification Service\nx20 instances]
    LB --> AdSvc[Ad Profile Service\nx3 instances]

    style FeedSvc fill:#4CAF50,color:#fff
    style NotifSvc fill:#2196F3,color:#fff
    style ImgSvc fill:#FF9800,color:#fff
    style AdSvc fill:#9C27B0,color:#fff

Governance

Governance refers to the rules, structures, and processes controlling how teams work. It’s one of the most powerful benefits of microservices.

Value Streams

Each Globomantics domain represents a value stream — a distinct value contribution:

Value StreamBusiness Value
Fast, smooth feedMore ad exposure → more revenue
Precise ad targetingHigher rates charged to advertisers
Effective content moderationReduced legal risk, user retention
Real-time notificationsUser engagement and retention

Conway’s Law

“Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.” — Melvin Conway

Microservices allow aligning organizational structure with software architecture: each team is responsible for one or more services corresponding to a business bounded context.


Module 3 — Communication Patterns

Distributed Systems and Latency

A microservices architecture is by definition a distributed system — a system composed of distinct nodes separated by a network.

Network Latency

ContextTypical Latency
Local RAM access~1–10 nanoseconds
Same Kubernetes cluster / same cloud region~1–5 milliseconds
Multi-region~10–100+ milliseconds

Network latency is hundreds of thousands to millions of times slower than local memory access. Every network hop accumulates.

Availability

Availability is measured as a percentage of successful responses:

AvailabilityDowntime / year
99%~3.65 days
99.9%~8.7 hours
99.99%~52 minutes
99.999%~5 minutes

The cascading dependencies problem:

If Service A depends on B, C, and D, each with 99.9% availability:

$$\text{Availability}_A = 0.999 \times 0.999 \times 0.999 \approx 99.7%$$

Overall availability degrades with every added synchronous dependency.

RPC Communications

Remote Procedure Call (RPC) is the simplest form of communication between microservices: a client sends a request to a server and waits for its response.

Common examples:

  • REST endpoints (HTTP/JSON)
  • gRPC (Google’s framework — Protocol Buffers, HTTP/2)
  • GraphQL

When to Use RPC?

ConditionRecommendation
High server availability✅ RPC suitable
Low or tolerable latency✅ RPC suitable
Simple and stable dependencies✅ RPC suitable
Low server availability❌ Prefer async
Complex and numerous dependencies❌ Prefer messaging
Long operations (e.g., report generation)❌ Prefer async
sequenceDiagram
    participant C as Client Service
    participant S as Server Service

    C->>S: HTTP POST /api/resource (Request)
    S-->>C: HTTP 200 OK (Response)
    Note over C,S: Synchronous communication — client waits

Service Discovery and Service Meshes

In microservices, a service must know the IP address of another service to communicate with it — this is the Service Discovery problem.

Service Discovery Approaches

ApproachDescriptionLimitations
DNS-basedName to IP resolution (built into Kubernetes)Insufficient for complex scenarios
Client-side discoveryClient consults a registry (e.g., Eureka)Discovery logic in each client
Server-side discoveryA load balancer does the resolutionPotential single point of failure
Service MeshTransparent sidecar proxy (e.g., Istio)Increased operational complexity

Service Meshes

Service meshes (Istio, Consul, OpenShift, Rancher) go beyond simple discovery:

  • Dynamic load shifting — Dynamic traffic redistribution
  • Failover — Automatic failover on failure
  • A/B Testing / Canary Releases — Traffic routing to different versions
  • mTLS Security — Service-to-service encryption and authentication
  • Observability — Metrics, traces, logs automatically enriched

Important trade-off: A service mesh adds operational complexity. Only adopt a service mesh if you have clear, current needs that justify it.

Message-driven Communication

Message-driven communication uses a message broker as an intermediary between producers and consumers. Also known as:

  • Event-driven architecture
  • Message-oriented architecture
  • Publish/Subscribe (pub/sub)

RPC vs Message-driven Comparison

sequenceDiagram
    participant P as Producer Service
    participant B as Message Broker
    participant C1 as Consumer 1
    participant C2 as Consumer 2

    P->>B: publish(PhotoUploadedEvent)
    Note over P,B: Fire and forget — no waiting for response
    B-->>C1: deliver(PhotoUploadedEvent)
    B-->>C2: deliver(PhotoUploadedEvent)
    C1->>B: publish(NotificationSentEvent)
    C2->>B: publish(ContentScanCompleteEvent)

Message-driven Advantages

  1. Elimination of cascade failures — Broker absorbs load spikes and temporary outages
  2. Loose coupling — A service publishes without knowing who consumes
  3. Spike absorption — Broker acts as a buffer (queue)
  4. Observability — Queue depth is a very useful operational metric

Example: Photo Upload at Globomantics

flowchart TD
    User([User]) --> API[API Service]
    API --> |"publish(PhotoUploaded)"| Broker[(Message Broker\nKafka/RabbitMQ)]

    Broker --> ContentScan[Content Moderation Service]
    Broker --> NotifSvc[Notification Service]
    Broker --> AdProfile[Ad Profile Service]
    Broker --> Storage[Storage Service]

    ContentScan --> |"publish(ContentScanResult)"| Broker
    Storage --> |"publish(StorageComplete)"| Broker

Service Dependencies and Coupling

Coupling between services is understood through their dependencies. A Service A that depends on the APIs of Services B and C is coupled to them.

The Breaking Changes Problem

When Service B needs to publish an incompatible change (breaking change), it cannot deploy without coordinating with Service A — which breaks independence.

Solution: API Versioning

graph LR
    A[Service A] --> |"GET /api/v1/users"| B_v1[Service B\nAPI v1 — deprecated]
    A2[Service A\nupdated] --> |"GET /api/v2/users"| B_v2[Service B\nAPI v2 — current]

    B_v1 -.->|"evolves to"| B_v2

Versioning strategy:

  1. Service B publishes the breaking change in a new version /api/v2/
  2. The old version /api/v1/ remains available but deprecated
  3. Consumers receive deprecation warnings
  4. Service A prioritizes migration to /api/v2/
  5. Once all consumers migrated, /api/v1/ is removed

Module 4 — Adopting Microservices

DORA Metrics — Assessing Capabilities

Before adopting microservices, assess whether the organization has the necessary capabilities. Microservices are much more complex to build and operate than a monolithic architecture.

The DevOps Research and Assessment (DORA) program defines 4 key metrics:

DORA MetricDescriptionElite Target
Deployment FrequencyFrequency of production deploymentsMultiple times per day
Lead Time for ChangesTime from commit to productionLess than one day
Change Failure Rate% of deployments requiring immediate remediation0–15%
Mean Time to Recovery (MTTR)Average time to restore service after incidentLess than one hour

Organizational Prerequisites

  • Automated and reliable CI/CD pipelines
  • Complete test automation (unit, integration, end-to-end)
  • Infrastructure as Code for reproducible deployments
  • Robust monitoring and alerting
  • Culture of blameless post-mortems and continuous improvement

Common Pitfalls

Gall’s Law

“A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a working simple system.” — John Gall

Common Pitfalls to Avoid

PitfallDescriptionRecommendation
Too big, too fastMoving from monolith to dozens of microservices at onceMigrate progressively, service by service
Over-engineering messagingAdopting an event broker without mastering async patternsStart with simple RPC, add messaging as needed
Unfamiliar data storageUsing a new DB technology for each serviceMaster known technologies first
Premature service meshAdopting Istio/Consul without a clear needUse DNS-based discovery until you need more
Distributed monolithTightly coupled services that deploy togetherReview bounded contexts, reduce coupling
Neglecting observabilityNo centralized logs, no distributed tracingImplement logging, metrics, tracing from the start
Ignoring DORA metricsNot measuring delivery capabilitiesTrack the 4 DORA metrics regularly

The Strangler Fig Pattern

For progressively migrating from a monolith to microservices:

flowchart LR
    Client([Client]) --> Proxy[Proxy / API Gateway]
    Proxy --> |"New functionality"| NewSvc[New Microservice]
    Proxy --> |"Old functionality"| Monolith[Existing Monolith]
    
    style NewSvc fill:#4CAF50,color:#fff
    style Monolith fill:#FF5722,color:#fff

Progressively, the monolith shrinks and microservices grow.

Further Resources

BookAuthor(s)Theme
The Software Architect ElevatorGregor HohpeTechnical leadership, communication, architect coaching
Microservices PatternsChris RichardsonTactical patterns with diagrams and code samples
Site Reliability EngineeringBeyer, Jones, Petoff, MurphyOperating complex systems, SRE at Google

Architecture Diagrams

API Gateway Pattern

graph TD
    WebApp([Web App]) --> GW[API Gateway]
    MobileApp([Mobile App]) --> GW
    ThirdParty([Third-party Client]) --> GW

    GW --> |"Auth check"| AuthSvc[Auth Service]
    GW --> |"/api/users/*"| UserSvc[User Service]
    GW --> |"/api/orders/*"| OrderSvc[Order Service]
    GW --> |"/api/products/*"| ProductSvc[Product Service]
    GW --> |"/api/payments/*"| PaySvc[Payment Service]

    UserSvc --- UserDB[(Users DB)]
    OrderSvc --- OrderDB[(Orders DB)]
    ProductSvc --- ProductDB[(Products DB)]
    PaySvc --- PayDB[(Payments DB)]

    style GW fill:#FF9800,color:#fff
    style AuthSvc fill:#F44336,color:#fff

Circuit Breaker Pattern

stateDiagram-v2
    [*] --> Closed: Initial state
    
    Closed --> Open: Failure threshold reached\n(e.g.: 5 failures in 10s)
    Open --> HalfOpen: After timeout\n(e.g.: 30 seconds)
    HalfOpen --> Closed: Test request succeeds
    HalfOpen --> Open: Test request fails
    
    note right of Closed
        All requests pass through
        Errors are counted
    end note
    
    note right of Open
        All requests fail immediately
        No call to degraded service
        (Fast fail)
    end note
    
    note right of HalfOpen
        One test request passes
        to verify recovery
    end note

Saga Pattern (Choreography-based)

sequenceDiagram
    participant OS as Order Service
    participant PS as Payment Service
    participant IS as Inventory Service
    participant NS as Notification Service

    OS->>+PS: OrderCreated event
    PS-->>-OS: PaymentProcessed event
    OS->>+IS: ReserveInventory event
    IS-->>-OS: InventoryReserved event
    OS->>NS: OrderConfirmed event
    NS-->>OS: NotificationSent event

    Note over OS,NS: Each service reacts to events\nNo central coordinator

    rect rgb(255, 200, 200)
        OS->>PS: (on failure) OrderCancelled event
        PS-->>OS: PaymentRefunded event
        Note over OS,PS: Compensating transactions on failure
    end

Reference Tables

Microservices Patterns

PatternPurposeWhen to Use
API GatewaySingle entry point for clientsMultiple clients, cross-cutting concerns
Circuit BreakerPrevent cascade failuresServices with availability issues
SagaDistributed transactionsMulti-service business operations
Strangler FigProgressive migration from monolithLegacy modernization
SidecarInject infrastructure featuresLogging, monitoring, service mesh
Event SourcingStore state as eventsAudit trail, temporal queries
CQRSSeparate read and write modelsHigh performance reads + writes

Communication Comparison

AspectRPC (Synchronous)Message-driven (Async)
CouplingTightLoose
Availability dependencyYesNo
Response timeImmediateDeferred
ComplexityLowMedium to high
Use casesSimple queriesComplex workflows
ResilienceLowerHigher
ObservabilityDirectQueue depth as indicator

DORA Metrics Reference

MetricLow PerformerMediumHighElite
Deployment Frequency< 1/month1/month–1/week1/week–1/dayMultiple/day
Lead Time> 6 months1 month–6 months1 week–1 month< 1 day
MTTR> 1 week1 day–1 week< 1 day< 1 hour
Change Failure Rate46–60%16–45%16–30%0–15%
mindmap
  root((Microservices))
    Architecture
      Bounded Context
      Domain-Driven Design
      Independent Services
    Communication
      RPC
        REST
        gRPC
        GraphQL
      Async
        Pub/Sub
        Event-driven
        Message Broker
      Service Discovery
        DNS
        Service Mesh
    Patterns
      API Gateway
      Circuit Breaker
      Saga
      Event Sourcing
      CQRS
      Strangler Fig
    Benefits
      Complexity Management
      Independent Scaling
      Team Autonomy
      Technology Freedom
    Prerequisites
      CI/CD Pipelines
      Test Automation
      IaC
      DORA Metrics
      DevOps Culture
    Ecosystem
      Docker
      Kubernetes
      Kafka
      Istio
      Cloud Providers

Note: Microservices are among the most complex systems ever built. Organizations like Google, Netflix, Spotify, and Amazon use this approach at very large scale. Independence — of both services AND teams — is the key to success in microservices architectures.


Search Terms

microservices · foundations · java · backend · architecture · full-stack · web · communication · pattern · service · message-driven · rpc · scale · comparison · discovery · dora · globomantics · independent · latency · law · meshes · metrics · network · patterns

Interested in this course?

Contact us to book it or get a custom training plan for your team.