Skip to content

Commit 3679219

Browse files
authored
Add postgres/mysql CDC cookbooks (#530)
1 parent 5939372 commit 3679219

6 files changed

Lines changed: 463 additions & 0 deletions

File tree

mysql/cdc/.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MYSQL_PASS=spice

mysql/cdc/README.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# MySQL CDC (Binlog Replication)
2+
3+
Works with `v2.2.0+`
4+
5+
This recipe demonstrates how to stream real-time changes from a MySQL table into Spice using native Change Data Capture (CDC) over the MySQL [binary log](https://dev.mysql.com/doc/refman/8.0/en/binary-log.html). Inserts, updates, and deletes propagate automatically to the Spice accelerator — no Debezium or Kafka required.
6+
7+
Spice reads the binlog directly and applies row-level changes by primary key. The current binlog file and position are checkpointed in a client-side sidecar table so streaming resumes from where it left off after a restart.
8+
9+
## Prerequisites
10+
11+
- [Docker](https://docs.docker.com/get-docker/) is installed
12+
- Spice is installed (see the [Getting Started](https://docs.spiceai.org/getting-started) documentation)
13+
14+
> **Note:** MySQL CDC requires the server to be running with row-based binary logging enabled (`log_bin=ON`, `binlog_format=ROW`, `binlog_row_image=FULL`). MySQL 8.0+ enables `log_bin` and `binlog_format=ROW` by default; this recipe passes the flags explicitly so the requirement is clear. GTID-based positioning is not required.
15+
16+
---
17+
18+
## Step 1. Start MySQL with binary logging enabled
19+
20+
```bash
21+
docker run -d --name mysql-cdc \
22+
-e MYSQL_ROOT_PASSWORD=spice \
23+
-e MYSQL_DATABASE=spice_demo \
24+
-p 3308:3306 \
25+
mysql:8.0 \
26+
--server-id=1 \
27+
--log-bin=mysql-bin \
28+
--binlog-format=ROW \
29+
--binlog-row-image=FULL
30+
```
31+
32+
Wait a few seconds for MySQL to finish initializing, then confirm binary logging is active (`log_bin` should be `ON` and `binlog_format` should be `ROW`):
33+
34+
```bash
35+
docker exec mysql-cdc mysql -uroot -pspice \
36+
-e "SHOW VARIABLES WHERE Variable_name IN ('log_bin','binlog_format','binlog_row_image');"
37+
```
38+
39+
```console
40+
+-------------------+-------+
41+
| Variable_name | Value |
42+
+-------------------+-------+
43+
| binlog_format | ROW |
44+
| binlog_row_image | FULL |
45+
| log_bin | ON |
46+
+-------------------+-------+
47+
```
48+
49+
---
50+
51+
## Step 2. Create a replication user and seed the table
52+
53+
Spice connects with a user that can read the binlog. The minimum privileges are `REPLICATION SLAVE`, `REPLICATION CLIENT`, and `SELECT`.
54+
55+
```bash
56+
docker exec -i mysql-cdc mysql -uroot -pspice <<'EOF'
57+
CREATE USER 'spice'@'%' IDENTIFIED BY 'spice';
58+
GRANT REPLICATION SLAVE, REPLICATION CLIENT, SELECT ON *.* TO 'spice'@'%';
59+
FLUSH PRIVILEGES;
60+
61+
USE spice_demo;
62+
CREATE TABLE orders (
63+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
64+
customer VARCHAR(255),
65+
amount DECIMAL(10,2),
66+
status VARCHAR(32)
67+
);
68+
INSERT INTO orders (customer, amount, status) VALUES
69+
('Alice', 99.99, 'pending'),
70+
('Bob', 149.50, 'pending'),
71+
('Charlie', 299.00, 'shipped');
72+
SELECT CONCAT('Seeded ', COUNT(*), ' orders') AS result FROM orders;
73+
EOF
74+
```
75+
76+
---
77+
78+
## Step 3. Start the Spice runtime
79+
80+
```bash
81+
spice run
82+
```
83+
84+
You should see the dataset bootstrap from a consistent snapshot and then transition to live binlog streaming:
85+
86+
```
87+
2025-01-13T12:00:00Z INFO runtime::init::dataset: Initializing dataset orders
88+
2025-01-13T12:00:00Z INFO runtime::init::dataset: Dataset orders registered (mysql:spice_demo.orders), acceleration (duckdb:file, changes).
89+
2025-01-13T12:00:00Z INFO runtime::dataconnector::mysql: Bootstrapping MySQL table orders, records=3
90+
2025-01-13T12:00:00Z INFO runtime::dataconnector::mysql: Bootstrap complete for orders. Streaming binlog changes.
91+
2025-01-13T12:00:00Z INFO runtime: All components are loaded. Spice runtime is ready!
92+
```
93+
94+
---
95+
96+
## Step 4. Query the initial snapshot
97+
98+
In a new terminal, open the Spice SQL REPL:
99+
100+
```bash
101+
spice sql
102+
```
103+
104+
```sql
105+
SELECT * FROM orders;
106+
```
107+
108+
```console
109+
+----+-----------+--------+---------+
110+
| id | customer | amount | status |
111+
+----+-----------+--------+---------+
112+
| 1 | Alice | 99.99 | pending |
113+
| 2 | Bob | 149.50 | pending |
114+
| 3 | Charlie | 299.00 | shipped |
115+
+----+-----------+--------+---------+
116+
117+
Time: 0.008 seconds. 3 rows.
118+
```
119+
120+
---
121+
122+
## Step 5. Insert a record and see it stream
123+
124+
```bash
125+
docker exec mysql-cdc mysql -uroot -pspice -e \
126+
"INSERT INTO spice_demo.orders (customer, amount, status) VALUES ('Diana', 74.00, 'pending');"
127+
```
128+
129+
Query again in the SQL REPL:
130+
131+
```sql
132+
SELECT * FROM orders;
133+
```
134+
135+
```console
136+
+----+-----------+--------+---------+
137+
| id | customer | amount | status |
138+
+----+-----------+--------+---------+
139+
| 1 | Alice | 99.99 | pending |
140+
| 2 | Bob | 149.50 | pending |
141+
| 3 | Charlie | 299.00 | shipped |
142+
| 4 | Diana | 74.00 | pending |
143+
+----+-----------+--------+---------+
144+
145+
Time: 0.006 seconds. 4 rows.
146+
```
147+
148+
---
149+
150+
## Step 6. Update a record and see the change
151+
152+
```bash
153+
docker exec mysql-cdc mysql -uroot -pspice -e \
154+
"UPDATE spice_demo.orders SET status = 'shipped' WHERE customer = 'Alice';"
155+
```
156+
157+
```sql
158+
SELECT customer, status FROM orders WHERE customer = 'Alice';
159+
```
160+
161+
```console
162+
+----------+---------+
163+
| customer | status |
164+
+----------+---------+
165+
| Alice | shipped |
166+
+----------+---------+
167+
168+
Time: 0.005 seconds. 1 rows.
169+
```
170+
171+
---
172+
173+
## Step 7. Delete a record and see it removed
174+
175+
```bash
176+
docker exec mysql-cdc mysql -uroot -pspice -e \
177+
"DELETE FROM spice_demo.orders WHERE customer = 'Bob';"
178+
```
179+
180+
```sql
181+
SELECT * FROM orders;
182+
```
183+
184+
```console
185+
+----+-----------+--------+---------+
186+
| id | customer | amount | status |
187+
+----+-----------+--------+---------+
188+
| 1 | Alice | 99.99 | shipped |
189+
| 3 | Charlie | 299.00 | shipped |
190+
| 4 | Diana | 74.00 | pending |
191+
+----+-----------+--------+---------+
192+
193+
Time: 0.006 seconds. 3 rows.
194+
```
195+
196+
---
197+
198+
## Step 8. Cleanup
199+
200+
```bash
201+
docker rm -f mysql-cdc
202+
```
203+
204+
---
205+
206+
## Additional Resources
207+
208+
- [MySQL Data Connector documentation](https://docs.spiceai.org/components/data-connectors/mysql)
209+
- [MySQL Data Connector cookbook](../connector/README.md)
210+
- [MongoDB Change Streams cookbook](../../mongodb/change-streams/README.md)

mysql/cdc/spicepod.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
version: v1
2+
kind: Spicepod
3+
name: mysql-cdc
4+
5+
datasets:
6+
- from: mysql:spice_demo.orders
7+
name: orders
8+
params:
9+
mysql_host: localhost
10+
mysql_tcp_port: 3308
11+
mysql_db: spice_demo
12+
mysql_sslmode: disabled
13+
mysql_user: spice
14+
mysql_pass: ${secrets:MYSQL_PASS}
15+
acceleration:
16+
enabled: true
17+
engine: duckdb
18+
mode: file
19+
refresh_mode: changes
20+
primary_key: id
21+
on_conflict:
22+
id: upsert

postgres/cdc/.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PG_PASS=spice

0 commit comments

Comments
 (0)