|
| 1 | +--- |
| 2 | +icon: arrows-rotate |
| 3 | +description: Replicate committed changes from operational databases into an accelerated, query-ready replica using change data capture |
| 4 | +--- |
| 5 | + |
| 6 | +# Database Replication and CDC |
| 7 | + |
| 8 | +**Database replication** keeps an accelerated dataset continuously in step with its source by reading the source database's own changelog. Committed inserts, updates, and deletes are applied to the local replica within seconds, with no batch window and no external pipeline. |
| 9 | + |
| 10 | +The mechanism is **change data capture (CDC)**: rather than re-reading the source table on a schedule, Spice consumes the stream of changes the database already produces for its own recovery and replication — the PostgreSQL write-ahead log, a MongoDB change stream, a DynamoDB stream — and applies each change to the accelerator as it commits. |
| 11 | + |
| 12 | +Replication is enabled by setting `refresh_mode: changes` on an accelerated dataset. |
| 13 | + |
| 14 | +{% hint style="info" %} |
| 15 | +`changes` is one of three [refresh modes](data-acceleration/README.md#refresh-modes). Use `full` to replace a dataset on each refresh, `append` for immutable or time-series data, and `changes` to mirror a mutable source that emits a change feed. |
| 16 | +{% endhint %} |
| 17 | + |
| 18 | +### Why replicate |
| 19 | + |
| 20 | +Running analytical queries against a production database competes with transaction processing for the same connections, buffer pool, and CPU. The usual alternatives each carry a cost: |
| 21 | + |
| 22 | +* **ETL pipelines** add latency measured in minutes or hours, plus the infrastructure to build, schedule, and monitor them. |
| 23 | +* **Read replicas** relieve the primary but run the same row-oriented engine, so analytical scans remain slow. |
| 24 | +* **HTAP databases** require migrating off the existing system and couple transactional and analytical failure domains. |
| 25 | + |
| 26 | +CDC-based replication into a columnar accelerator avoids all three. The operational database keeps serving transactions, analytical load lands on separate storage and compute, and the replica stays seconds behind rather than hours. |
| 27 | + |
| 28 | +For the architecture built on this capability, see [Analytics Replica](../use-cases/analytics-replica.md). |
| 29 | + |
| 30 | +### Supported sources |
| 31 | + |
| 32 | +| Source | Mechanism | Configuration | |
| 33 | +| ------ | --------- | ------------- | |
| 34 | +| [PostgreSQL](../building-blocks/data-connectors/postgres.md) | Logical replication from the write-ahead log | `refresh_mode: changes` | |
| 35 | +| [MongoDB](../building-blocks/data-connectors/mongodb.md) | Change streams on the source collection | `refresh_mode: changes` | |
| 36 | +| [DynamoDB](../building-blocks/data-connectors/dynamodb.md) | DynamoDB Streams | `refresh_mode: changes` | |
| 37 | +| [Apache Kafka](../building-blocks/data-connectors/kafka.md) | Event stream consumption | `refresh_mode: append` | |
| 38 | +| [Debezium](../building-blocks/data-connectors/debezium.md) | Debezium change events over Kafka | `refresh_mode: changes` | |
| 39 | + |
| 40 | +{% hint style="info" %} |
| 41 | +Sources without a native Spice change feed — including MySQL and SQL Server — replicate through [Debezium](../building-blocks/data-connectors/debezium.md) over Kafka. |
| 42 | +{% endhint %} |
| 43 | + |
| 44 | +### Configuration |
| 45 | + |
| 46 | +A replicated dataset needs a `primary_key` so that updates and deletes can be matched to existing rows, and an `on_conflict` rule so that repeated keys upsert rather than duplicate. |
| 47 | + |
| 48 | +```yaml |
| 49 | +datasets: |
| 50 | + - from: postgres:public.orders |
| 51 | + name: orders |
| 52 | + params: |
| 53 | + pg_host: postgres.example-org.com |
| 54 | + pg_port: '5432' |
| 55 | + pg_user: spice |
| 56 | + pg_pass: ${secrets:pg_pass} |
| 57 | + pg_db: myapp |
| 58 | + pg_sslmode: verify-full |
| 59 | + acceleration: |
| 60 | + enabled: true |
| 61 | + engine: cayenne |
| 62 | + mode: file |
| 63 | + refresh_mode: changes |
| 64 | + primary_key: id |
| 65 | + on_conflict: |
| 66 | + id: upsert |
| 67 | +``` |
| 68 | +
|
| 69 | +On startup Spice loads an initial snapshot of the table, then switches to streaming changes. No `refresh_check_interval` is required — changes are applied as they arrive rather than on a poll. |
| 70 | + |
| 71 | +Any accelerator engine can back a replicated dataset. [Cayenne](../building-blocks/data-accelerators/cayenne.md) is built for this workload, sustaining a high-throughput change feed while serving analytical scans from the same table. |
| 72 | + |
| 73 | +### PostgreSQL prerequisites |
| 74 | + |
| 75 | +Logical replication must be enabled on the source server: |
| 76 | + |
| 77 | +``` |
| 78 | +wal_level = logical |
| 79 | +max_replication_slots = 10 |
| 80 | +max_wal_senders = 10 |
| 81 | +``` |
| 82 | + |
| 83 | +Each replicated table needs a primary key, or `REPLICA IDENTITY FULL`, so that updates and deletes carry enough information to identify the affected row: |
| 84 | + |
| 85 | +```sql |
| 86 | +ALTER TABLE public.orders REPLICA IDENTITY FULL; |
| 87 | +``` |
| 88 | + |
| 89 | +The connecting role needs the `REPLICATION` attribute, plus `SELECT` on the replicated tables. Spice creates and manages its own replication slot and publication. |
| 90 | + |
| 91 | +{% hint style="warning" %} |
| 92 | +An inactive replication slot causes the source server to retain write-ahead log segments indefinitely, which can exhaust disk on the primary. Drop the slot on the source if a replicated dataset is removed permanently. |
| 93 | +{% endhint %} |
| 94 | + |
| 95 | +### Handling deletes |
| 96 | + |
| 97 | +CDC propagates hard deletes, which sets replication apart from incremental ingestion. A `DELETE` on the source removes the row from the replica on the next change event, with no reconciling full refresh and no soft-delete convention in the source schema. |
| 98 | + |
| 99 | +Sources that expose no change feed at all — HTTP APIs, for example — use [incremental ingestion](data-acceleration/README.md#incremental-ingestion) with `refresh_mode: append` instead, where deletes are handled by soft-delete tombstones or a periodic full refresh. |
| 100 | + |
| 101 | +### Related |
| 102 | + |
| 103 | +* [Analytics Replica](../use-cases/analytics-replica.md) — the deployment pattern built on replication |
| 104 | +* [Data Acceleration](data-acceleration/README.md) — refresh modes, incremental ingestion, and retention |
| 105 | +* [Database CDN](../use-cases/database-cdn.md) — colocating a hot working set with an application |
| 106 | +* [Change data capture](https://spiceai.org/docs/features/cdc) in the Spice.ai OSS documentation |
0 commit comments