Polyglot persistence works only when ownership and synchronization are explicit.
Design a Polyglot Architecture with Explicit Ownership, Synchronization, SLOs, and Failure Boundaries
Assemble AtlasMart into a polyglot architecture with one authoritative owner per fact, acyclic synchronization, measurable freshness, rebuild paths, recovery objectives, and explicit failure boundaries.
Assign one authoritative owner for each AtlasMart business fact and distinguish authoritative stores from caches, search indexes, projections, telemetry stores, and graph views.
Draw synchronization as an acyclic dependency graph with source versions, freshness SLOs, idempotency, replay, rebuild, and reconciliation paths.
Attach consistency, RPO/RTO, security, observability, hot-key, partition, and failure-domain assumptions to each store rather than only to the system as a whole.
Diagnose cycles and ambiguous ownership that can create feedback loops, stale overwrites, and irreconcilable recovery decisions.
1. Polyglot persistence needs an ownership map
AtlasMart can now justify several persistence models, but “use the best database for each job” is incomplete. The architecture is safe only if each fact has a known authority. Orders, payments and inventory reservations may remain in a relational transaction boundary. Catalog aggregates may have a document authority. Sessions and rate limits may be intentionally ephemeral key-value state. Telemetry may be partitioned by device/time. Search and fraud graphs can be derived views.
The key phrase is derived view. Search must not become an accidental second writer of catalog price. Fraud graph edges should be reproducible from authoritative identity/order events. A cache may disappear without erasing business truth.
2. Synchronization should be directional and observable
Represent synchronization as a directed graph. Edges carry source versions or offsets. Consumers are idempotent. Every derived store has a freshness SLO, lag metric, rebuild source, reconciliation job and degraded-mode behavior. Avoid cycles unless there is a formally designed bidirectional conflict protocol; ordinary projections should be acyclic.
| Store | Role | Owner | Freshness/recovery | Failure behavior |
|---|---|---|---|---|
| Orders/payments/inventory | Authoritative | Checkout | Strong invariant; tight RPO/RTO | Degrade/stop unsafe writes |
| Catalog documents | Authoritative | Catalog | Versioned aggregate writes | Exact reads may remain available without search |
| Sessions/rate limits | Ephemeral | Identity/gateway | Loss tolerated within policy | Reauthenticate/reconstruct |
| Telemetry | Authoritative event history | Device ingest | Partition/time retention | Buffer/backpressure or controlled loss by policy |
| Search | Derived | Projection | Freshness SLO; rebuildable | Degraded exact lookup |
| Fraud graph | Derived | Fraud projection | Freshness SLO; rebuildable | Hold/review risky decisions if stale |
3. Deliberately wrong approach: derived-to-authoritative feedback
A developer lets the search index “correct” catalog prices because search has a convenient administration UI. Search is eventually consistent. A stale projection writes an old value back to catalog, which emits another event, which updates search again. The system now has a synchronization cycle and no clear conflict authority.
The repair is one-way authority: catalog owns catalog facts. Search can report drift but cannot mutate the source unless a deliberate business command returns through the owning service and passes its concurrency/invariant rules.
4. AtlasMart lab: detect cycles and survive loss of a derived store
Python 3.13+ standard library only. The architecture is represented as metadata plus a synchronization graph; no database products are required.
from collections import defaultdict, deque
stores = {
"orders": {"kind":"authoritative","owner":"checkout","freshness_s":0,"rpo_min":1,"rebuild":False},
"catalog": {"kind":"authoritative","owner":"catalog","freshness_s":0,"rpo_min":5,"rebuild":False},
"sessions": {"kind":"ephemeral","owner":"identity","freshness_s":0,"rpo_min":None,"rebuild":True},
"search": {"kind":"derived","owner":"search-projection","freshness_s":30,"rpo_min":None,"rebuild":True},
"fraud_graph": {"kind":"derived","owner":"fraud-projection","freshness_s":60,"rpo_min":None,"rebuild":True},
"telemetry": {"kind":"authoritative","owner":"device-ingest","freshness_s":0,"rpo_min":10,"rebuild":False},
}
edges=[
("catalog","search"),
("orders","search"),
("orders","fraud_graph"),
("catalog","fraud_graph"),
]
def has_cycle(edges):
g=defaultdict(list); indeg=defaultdict(int); nodes=set()
for a,b in edges:
g[a].append(b); indeg[b]+=1; nodes|={a,b}
q=deque([n for n in nodes if indeg[n]==0]); seen=0
while q:
n=q.popleft(); seen+=1
for m in g[n]:
indeg[m]-=1
if indeg[m]==0:q.append(m)
return seen!=len(nodes)
print("POLYGLOT OWNERSHIP")
for name,s in stores.items():
print(f"{name:12} {s['kind']:13} owner={s['owner']:18} freshness={s['freshness_s']}s rebuild={s['rebuild']}")
print("sync edges=",edges,"cycle=",has_cycle(edges))
print("\nWRONG DESIGN: search writes catalog price back to catalog")
wrong=edges+[("search","catalog")]
print("cycle=",has_cycle(wrong),"-- stale search data could overwrite authoritative catalog state")
print("\nFAILURE: search store lost")
search_available=False
print("checkout authoritative order path available=", True)
print("search available=",search_available,"degraded behavior=database-native exact catalog lookup")
print("repair=truncate/rebuild search from catalog + order change history, then reconcile source versions")
print("\nOWNERSHIP RULE")
print("derived stores never become fallback writers for authoritative facts")
The intended synchronization graph is acyclic. Adding
search → catalog creates a detectable cycle. When
search is declared unavailable, checkout remains authoritative
and the documented repair is rebuild from catalog/order
history plus source-version reconciliation.
5. Production judgment
A polyglot design is justified only if each extra store buys a measurable capability. Count not just database instances but contracts: schema evolution, identity/tenant policy, encryption keys, change streams, observability, backup/rebuild, incident ownership and on-call skills. More databases increase fault surfaces even when each individual product is managed.
Test failure boundaries independently. Kill the cache and prove reauthentication. Delete the search projection and rebuild it. Delay CDC and verify freshness alarms. Lose one telemetry node and confirm survivor headroom. Restore the order ledger in isolation and reconcile projections. Lesson 5 turns these mechanisms into the final architecture defense.
Check your understanding
- What is the simplest ownership rule in a polyglot architecture?
- Why are synchronization cycles dangerous?
- What should a derived store expose besides query results?
- Why attach RPO/RTO to stores individually?
- What is the fallback when a derived search store is lost?
Review the answers
1. Each business fact has one authoritative writer/system; other stores are explicitly derived, cached, replicated, or ephemeral copies.
2. A stale derived copy can feed back into its source or another projection, creating oscillation, overwrite loops, unclear conflict authority, and difficult recovery.
3. Source version/offset, freshness age, projection health, rebuild/reconciliation status, and relevant errors/lag.
4. Authoritative and reconstructable stores have different recovery obligations; a rebuildable search index does not need the same backup semantics as the orders ledger.
5. Serve an explicitly degraded path from authoritative data where feasible, rebuild the projection from retained source/change history, and reconcile before declaring freshness restored.
References
Foundational and current implementation references used for this lesson:
- PostgreSQL 18 — Transactions — Current official transaction semantics used as one relational implementation anchor.
- PostgreSQL 18 — Logical Replication — Current official snapshot-plus-change replication model relevant to migration and synchronization.
- Debezium 3.6 release series — Latest stable 3.6 line; 3.6.1.Final was released 2026-08-04. Optional CDC implementation anchor only.
- Apache Cassandra downloads — Current official release page listing Cassandra 5.0.9 as latest GA on 2026-08-07.
- Dynamo paper — Primary research illustrating application-aware distributed-data tradeoffs and conflict handling.
- Bigtable paper — Primary research for partitioned, high-throughput structured data.
- Neo4j — Graph data modeling — Current optional graph implementation reference; graph store in the lab remains a derived conceptual view.
- OpenSearch — Vector search — Current optional search/vector implementation reference; dedicated search remains a rebuildable derived store in the architecture.