RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Eruo Fredoline
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /Enterprise-Scale RAG
  6. /Ch. 3
Enterprise-Scale RAG

03. Microservices Decomposition

Chapter 3 of 24 · 15 min
KEY INSIGHT

Microservices solve scaling mismatches but introduce distributed systems complexity. Every service boundary is a potential failure point that needs explicit handling through idempotency, retries with backoff, and compensating transactions.

Monolithic RAG implementations fail at the seams where components have conflicting scaling needs. Your embedding service needs many CPU cores during business hours when documents upload in bulk, but your inference service needs GPU access whenever user queries arrive. Co-locating them means overprovisioning both.

Decompose into these services: Ingestion Service (handles document upload, parsing, chunking), Embedding Service (converts chunks to vectors), Index Service (manages vector database writes and index updates), Retrieval Service (handles search queries, access control filtering), Context Service (assembles LLM prompts with retrieved chunks).

Each service owns its data store. The Ingestion Service writes parsed documents to object storage. The Embedding Service writes vectors to the vector database. The Retrieval Service reads from both—but never writes.

# Service boundary violation example - DON'T DO THIS
class RetrievalService:
    def search(self, query: str, user_id: str):
        # Anti-pattern: retrieval service directly accessing 
        # document store it doesn't own
        doc = document_store.get(query.doc_id)  
        # Should only read through owned interfaces

The async boundary is critical. Direct synchronous calls between services create cascading timeouts. When the embedding service takes 2 seconds to embed a chunk (GPU contention), the ingestion service waits 2 seconds before processing the next document. With 1,000 concurrent uploads, this creates a backlog spiral.

Use async task queues between services. Ingestion publishes chunk events; Embedding subscribes and publishes vector events; Index subscribes and writes. Each service operates at its own pace.

Service discovery needs careful design. A naive approach hardcodes service URLs—but embedding service pods restart constantly in Kubernetes. A service mesh (Istio, Linkerd) handles this, but adds operational complexity.

The hardest problem is distributed transactions. When a document updates, you need to: delete old vectors, insert new vectors, update document metadata, invalidate cache entries, and publish a "document updated" event—all atomically. You cannot achieve true atomicity across services. Implement compensating transactions and idempotency keys instead.

Failure modes include orphaned vectors (embedding deleted but index entry remains), phantom documents (document store has it but vector search can't find it), and infinite retry loops when a service marks tasks as failed but never recovers.

EXERCISE

Map the data flow for updating a document that is currently indexed. Identify every service that must be involved and the minimum number of async operations required to achieve eventual consistency.

← Chapter 2
Distributed Architecture
Chapter 4 →
Event Queue with Kafka