Service Discovery & Database per Service Patterns — Interview Questions
Service Discovery — purpose, registries and health, client-side vs server-side discovery, tools (Eureka, Consul, Kubernetes DNS, etcd/ZooKeeper-style) and how discovery enables horizontal scaling — and Database per Service — why each service owns its data, the challenges of many databases, consistency strategies (sagas, outbox, events rather than 2PC), and replication/synchronisation (events, CDC with Debezium, event sourcing, CQRS read models).
Published September 25, 2026
How to use this lesson
The microservices chapter of this course covers discovery configuration and saga mechanics. This lesson answers the pattern-level questions:
why discovery exists, and how it enables elasticity;
why data ownership is the heart of microservices;
how to keep data in sync without sharing databases.
Q1. What is the Service Discovery pattern for?
Short answer: In dynamic environments, instances come and go: autoscaling, deployments, failures, and new IP addresses. Service discovery keeps a live registry of the healthy instances of each service. Instances register (or are registered by the platform), and clients or load balancers query it, so nobody hardcodes addresses. Example: a cloud inventory system scales its Stock service from 3 to 12 instances during a sale, and callers start using the new instances automatically.
Q2. What is the Database per Microservice pattern for?
Short answer:Each service owns its data store, private to it. Others access that data only through its API or events. This gives loose coupling, independent schema evolution, independent scaling, and polyglot persistence. Example: in ride-sharing, Booking uses a relational database for transactional integrity, while Driver Tracking uses a write-optimised NoSQL or time-series store (Cassandra, or Redis geo) for high-frequency location updates.
Q3. What is the purpose of the Service Discovery pattern in microservices?
Short answer: It's the system's dynamic address book, plus health filter:
It decouples callers from network locations: a logical name (inventory-service) maps to the current addresses.
It tracks health through heartbeats, TTLs or health checks, so traffic goes only to live instances.
It enables elasticity and zero-downtime deployments: new instances appear, and draining ones disappear, automatically.
It can carry metadata: version, zone, weights. That's used for canary routing and zone-aware balancing.
Q4. How do client-side and server-side service discovery differ?
Short answer:
Client-side: the caller queries the registry, and load-balances itself. Examples: the Eureka client with Spring Cloud LoadBalancer, or a Consul client.
Pros: no extra network hop; smart, per-client routing.
Cons: discovery logic in every client or language; clients are coupled to the registry.
Server-side: the caller sends to a router or load balancer (a Kubernetes Service, AWS ALB, a gateway, a mesh sidecar), which consults the registry and forwards the request.
Pros: thin, language-agnostic clients.
Cons: one more hop and component, which must be highly available.
Key points to cover:
A service mesh blurs the line: the sidecar next to the client does client-side balancing, transparently to the application.
Q5. Which tools are commonly used for service discovery?
Short answer:
Netflix Eureka:
An AP registry (it favours availability; its self-preservation mode keeps stale entries during network partitions).
Simple, and tightly integrated with Spring Cloud. It's JVM-centric.
HashiCorp Consul:
A CP registry, built on Raft.
Rich health checks, multi-datacenter support, a DNS and HTTP interface (language-agnostic), key/value configuration, and an optional service mesh (Consul Connect).
Kubernetes built-in:
Services + DNS (CoreDNS) + EndpointSlices, fed by readiness probes.
The default on Kubernetes, with no extra component.
Others:
etcd- or ZooKeeper-based registries (Apache Curator; Dubbo).
Cloud registries: AWS Cloud Map, with ECS service discovery.
Mesh control planes: Istio, Linkerd.
Q6. How does Service Discovery help with horizontal scaling?
Short answer: Scaling out means launching new instances, with new, unpredictable addresses. With discovery:
new instances register automatically once healthy (or become ready in Kubernetes);
callers and load balancers pick them up on the next registry refresh, and spread the traffic across all the instances;
on scale-in or failure, instances deregister (or miss heartbeats), and stop receiving traffic.
There are no configuration changes and no redeployments of callers, so autoscaling works end to end.
Key points to cover:
Registry and cache staleness: Eureka clients refresh every ~30 s by default, so dead instances can still get traffic briefly. Combine discovery with retries on a different instance, and with graceful shutdown (deregister first, then drain).
Q7. Why is a separate database for each microservice recommended?
Short answer:
Loose coupling: with a shared database, the schema is the API. Any team's migration can break other services, and deployments become coupled: a "distributed monolith".
Autonomy: each team evolves its schema, and deploys, on its own schedule.
Independent scaling and performance isolation: one service's heavy queries or locks don't slow the others.
The right technology: relational, document, key-value, search or graph, per need.
Security and blast radius: separate credentials, least privilege, and smaller compromise impact.
Clear ownership of data quality and semantics.
Key points to cover:
"Separate database" can mean a separate schema on a shared server. That's cheaper, but you must still enforce the no cross-access rule with credentials.
Q8. What are the challenges of managing multiple databases in microservices?
Short answer:
Distributed consistency: there are no cross-service ACID transactions, so you need sagas and eventual consistency.
Cross-service queries and joins are impossible directly. You need API composition, or read models.
Data duplication: services keep copies of others' data (customer names in Orders). They need sync mechanisms, and tolerance of staleness.
Operational overhead: many databases to provision, patch, back up, monitor and restore, possibly on several technologies. Managed cloud databases and automation help.
Reporting and analytics: you need a pipeline (CDC or events) into a data warehouse or lake.
Referential integrity across services isn't enforced by the database; it must be handled by design.
Cost, and skills across polyglot stores.
Q9. How do you handle data consistency across microservices with separate databases?
Short answer: Prefer event-driven eventual consistency, over distributed transactions:
Sagas (choreographed or orchestrated): local transactions plus compensations.
The transactional outbox, or CDC, to publish events atomically with the state change.
Idempotent consumers (at-least-once delivery), and ordering by key.
Explicit state machines with intermediate states (PENDING), and reconciliation jobs.
2PC/XA only when it's unavoidable. It's blocking, fragile at scale, and often unsupported (Kafka, many NoSQL and cloud databases).
Common trap: the source presents distributed transactions and events as equal options. In microservices, 2PC is the exception. Say why: availability and coupling.
Q10. What strategies can be used to replicate or synchronise data between microservices?
Short answer:
Domain events (application-published): the owner publishes CustomerUpdated, and consumers update their local read copies. Use the outbox for reliability. The events are meaningful business contracts.
Change Data Capture:Debezium reads the owner database's transaction log (binlog or WAL), and streams row changes to Kafka.
Pros: no application changes; it catches every change, including batch updates.
Cons: it exposes internal table structure. Mitigate with the outbox + Debezium outbox router, which publishes curated events.
Event sourcing: the owner stores events as its source of truth. Other services subscribe, and can rebuild their projections by replaying.
CQRS read models: a query service builds denormalised views from events of several services (for example "orders with customer and shipment status").
API calls with caching: fetch on demand, with a TTL cache. Simple, but a runtime dependency.
Batch or ETL synchronisation, for non-real-time needs (reporting).
Key points to cover:
Design for idempotency, ordering per entity (key by ID), schema evolution (a registry, compatibility rules), replays and backfills, and eventual-consistency UX.
Follow-up questions this topic invites — and their answers
Q: Is Eureka AP or CP, and why does it matter?
A: AP. During a partition, Eureka keeps serving possibly-stale registrations (self-preservation), rather than deregistering everything. That's good for availability, but callers may hit dead instances, so pair it with retries and timeouts. Consul (Raft) is CP: consistent, but a registry that loses its quorum can't accept registrations.
Q: What's the difference between CDC and the transactional outbox?
A: CDC streams raw table changes from the log. The outbox stores explicit domain events in a table inside the business transaction. Debezium can relay the outbox table, which combines the reliability of log-based capture with well-designed event contracts.
Q: How stale can replicated data be, and how do you deal with it?
A: Usually milliseconds to seconds, and more during incidents. Design user flows to tolerate it (show "processing"), re-validate critical facts with the owner at decision time (for example the price at checkout), and monitor replication or consumer lag.
Q: Can two services share a read-only reference database?
A: Sometimes, for truly static reference data (country codes). Prefer publishing it as a library, a config artifact or events. Once it becomes mutable business data, give it a single owner.