Key Concepts of Microservices Architecture Explained Through System Design Notes

The liquidslr/system-design-notes repository presents microservices architecture through six core concepts: service decomposition by business capability, API Gateway fronting, gRPC-based internal communication, database-per-service ownership with saga/2PC transaction patterns, horizontal scalability via sharding and caching, and event-driven consistency using CDC pipelines.

The open-source liquidslr/system-design-notes repository provides practical, interview-focused guidance on distributed systems. Its implementations of the Hotel Reservation System and Digital Wallet demonstrate how to apply microservices principles to real-world scenarios, grounded in actual design documents and code patterns.

Service Decomposition by Business Capability

The repository emphasizes bounded contexts as the foundation of microservices design. In 22. Hotel Reservation System/README.md, the system breaks down into discrete, single-responsibility services:

  • Hotel service – manages hotel metadata and availability
  • Rate service – handles pricing and rate calculations
  • Reservation service – processes booking transactions
  • Payment service – coordinates financial operations
  • Hotel management service – handles administrative functions

Each service encapsulates its own business logic and data access patterns, preventing the tight coupling that characterizes monolithic architectures.

API Gateway as the Security and Routing Layer

All external traffic enters through a Public API Gateway, described in the Hotel Reservation System's high-level design. This component centralizes cross-cutting concerns before requests reach internal services:

  • Authentication and authorization – validating JWT tokens or API keys
  • Rate limiting – preventing abuse through throttling (referenced in 04. Rate Limiter/Readme.md)
  • Request routing – directing traffic to the appropriate downstream service
  • SSL termination – handling HTTPS encryption at the edge

The gateway insulates microservices from client-facing protocols, allowing internal services to use optimized communication mechanisms.

Inter-Service Communication with gRPC

While external clients interact via REST, internal service-to-service calls leverage RPC frameworks for efficiency. The repository specifically recommends gRPC, as noted in the Hotel Reservation System documentation: "Inter-service communication can be facilitated via a RPC framework, such as gRPC."

Protocol Buffers define service contracts with strict type safety:

// proto/reservation.proto
syntax = "proto3";

service ReservationService {
  rpc CreateReservation (ReservationRequest) returns (ReservationResponse);
}

message ReservationRequest {
  string hotel_id = 1;
  string room_type_id = 2;
  string start_date = 3;
  string end_date   = 4;
  int32  room_count  = 5;
  string idempotency_key = 6;
}

message ReservationResponse {
  string reservation_id = 1;
  string status = 2;
}

The Node.js implementation demonstrates unary RPC calls between services:

// services/reservation-service/server.js
const grpc = require('@grpc/grpc-js')
const protoLoader = require('@grpc/proto-loader')
const packageDef = protoLoader.loadSync('proto/reservation.proto')
const grpcObj = grpc.loadPackageDefinition(packageDef)
const reservation = grpcObj.ReservationService

function createReservation(call, callback) {
  const req = call.request
  // Idempotency check against DB using req.idempotency_key
  // Business logic implementation...
  callback(null, { reservation_id: 'abc123', status: 'CONFIRMED' })
}

const server = new grpc.Server()
server.addService(reservation.service, { CreateReservation: createReservation })
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
  server.start()
  console.log('Reservation gRPC service running')
})

Data Ownership and Distributed Transaction Patterns

The repository advocates for database-per-service architecture to ensure loose coupling. However, when services must maintain consistency across boundaries, it presents two distinct patterns:

Saga Pattern – Implemented in 27. Digital Wallet/README.md, this orchestrates long-running transactions through a sequence of local transactions with compensating actions for rollback.

Two-Phase Commit (2PC) – Mentioned in the Hotel Reservation System for scenarios requiring strict ACID guarantees across services.

The saga orchestrator pseudo-code illustrates failure handling:

// orchestrator/saga.js
async function bookHotelReservation(payload) {
  // Step 1 – Reserve inventory
  await http.post('/v1/reservations', payload)

  // Step 2 – Charge payment
  try {
    await http.post('/v1/payments', { reservationId: payload.id })
  } catch (err) {
    // Compensating transaction: cancel reservation
    await http.delete(`/v1/reservations/${payload.id}`)
    throw err
  }
}

Scalability Through Sharding and Caching

Stateful components require horizontal scaling strategies. The repository details sharding by hotel_id in the Hotel Reservation System's scalability section, distributing data across multiple database instances to handle increased load.

Caching layers using Redis reduce database pressure, while stateless service design enables replication without session affinity. The architecture diagrams in 22. Hotel Reservation System/README.md illustrate how CDN and application caching combine to optimize read-heavy workloads.

Concurrency Control and Idempotency

Distributed systems must handle double-submit scenarios and race conditions. The repository addresses this in the "Concurrency issues" subsection through:

  • Idempotency keys – UUIDs passed in requests (visible in the gRPC proto definition) that allow services to detect duplicate operations
  • Optimistic locking – versioning records to prevent lost updates
  • Pessimistic locking – database-level locks for critical inventory operations
  • Database constraints – unique indexes preventing duplicate bookings

Event-Driven Consistency with Change Data Capture

To maintain data synchronization without tight coupling, the repository implements Change Data Capture (CDC) using Debezium. This pattern streams database updates to message brokers, enabling eventual consistency across services while keeping them decoupled.

As described in the Hotel Reservation System's "Data consistency among services" section, CDC propagates write operations to caches and search indexes asynchronously, ensuring read models stay synchronized with the source of truth.

Practical Implementation Example

A minimal Node.js/Express service demonstrates the repository's architectural principles:

// services/hotel-service/index.js
const express = require('express')
const app = express()
app.use(express.json())

// Service-owned data (isolated from other services)
const hotels = [{ id: 1, name: 'Grand Plaza' }]

// REST endpoint exposed behind API Gateway
app.get('/v1/hotels/:id', (req, res) => {
  const hotel = hotels.find(h => h.id === Number(req.params.id))
  if (!hotel) return res.status(404).send({ error: 'Not found' })
  res.send(hotel)
})

app.listen(3000, () => console.log('Hotel service listening on :3000'))

Summary

The liquidslr/system-design-notes repository demonstrates that production-ready microservices require more than just code separation:

  • Business capability boundaries define service granularity, as shown in the Hotel Reservation System's decomposition into five distinct services
  • API Gateways handle cross-cutting concerns, allowing services to focus on domain logic
  • gRPC provides efficient, typed internal communication compared to REST
  • Database-per-service with sagas or two-phase commit maintains data integrity across distributed transactions
  • Horizontal scaling via sharding (by hotel_id) and Redis caching addresses stateful service growth
  • Idempotency keys and distributed locking prevent concurrency anomalies in reservation systems
  • CDC pipelines enable asynchronous consistency without service coupling

Frequently Asked Questions

What is the difference between sagas and two-phase commit in microservices?

According to the Digital Wallet and Hotel Reservation System designs, sagas manage long-running transactions through a series of local operations with compensating rollbacks, suitable for eventual consistency scenarios. Two-phase commit (2PC) provides strict ACID guarantees across services but introduces blocking and coordinator failure risks, making it appropriate only when absolute consistency outweighs availability concerns.

Why does the repository recommend gRPC over REST for internal service communication?

The Hotel Reservation System documentation suggests gRPC because it offers binary Protocol Buffer serialization (reducing payload size), HTTP/2 multiplexing (enabling concurrent streams), and strongly typed contracts (preventing integration errors). While REST remains the standard for external client interfaces, gRPC's performance characteristics better suit high-volume internal traffic between microservices.

How does the API Gateway pattern differ from a simple load balancer?

In 04. Rate Limiter/Readme.md and the Hotel Reservation System design, the API Gateway operates at the application layer (Layer 7), handling authentication, rate limiting, request routing, and protocol translation. A load balancer typically operates at the transport layer (Layer 4), distributing traffic based on health checks and algorithms without inspecting request content or enforcing security policies.

What is the significance of database-per-service in the repository's architecture?

As implemented in the Hotel Reservation System, database-per-service ensures each microservice owns its data storage, preventing tight coupling through shared database schemas. This isolation allows teams to choose optimal storage technologies (SQL vs. NoSQL) for each domain and enables independent scaling, though it necessitates patterns like sagas or CDC to maintain consistency across service boundaries.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →