Idempotency
Bạn sẽ học được
- Idempotency là gì trong bối cảnh pipeline.
- Ba mẫu ghi dữ liệu an toàn khi chạy lại.
- Vì sao
INSERTthường là nguyên nhân gây trùng dữ liệu. - Kiểm tra tính idempotent bằng cách chạy hai lần.
- Áp dụng cho bảng partition và bảng upsert.
Khái niệm cốt lõi
Một task là idempotent nếu chạy lại cùng một logical date cho ra cùng một kết quả, không tạo thêm dữ liệu.
Chạy 1 lần: 12.000 dòng
Chạy 2 lần: 12.000 dòng ← idempotent
Chạy 2 lần: 24.000 dòng ← không idempotentĐiều này quan trọng vì Airflow sẽ chạy lại: khi task thất bại và retry, khi bạn backfill, khi sửa bug và chạy lại một ngày.
Pipeline không idempotent biến một lần retry thành một sự cố dữ liệu.
Ba mẫu an toàn
1. Xoá partition rồi ghi lại
Phù hợp với bảng partition theo ngày:
DELETE FROM fact_orders WHERE order_date = '2026-03-01';
INSERT INTO fact_orders (order_date, order_id, amount)
SELECT order_date, order_id, amount
FROM staging_orders
WHERE order_date = '2026-03-01';Hai câu trong một transaction. Nếu INSERT lỗi, DELETE phải rollback, nếu không ngày đó mất sạch dữ liệu.
2. MERGE (upsert)
Phù hợp khi bảng không partition hoặc cần cập nhật từng dòng:
MERGE INTO fact_orders AS t
USING staging_orders AS s
ON t.order_id = s.order_id
AND t.order_date = s.order_date
WHEN MATCHED THEN
UPDATE SET amount = s.amount, updated_at = now()
WHEN NOT MATCHED THEN
INSERT (order_date, order_id, amount, updated_at)
VALUES (s.order_date, s.order_id, s.amount, now());Điều kiện ON phải là khoá duy nhất. Nếu khoá trùng trong staging, MERGE có thể lỗi hoặc cập nhật nhiều lần.
3. Ghi ra bảng mới rồi đổi tên
Phù hợp với bảng lớn, tránh khoá bảng lâu:
CREATE TABLE fact_orders_new AS SELECT ...;
-- kiểm tra số dòng
DROP TABLE fact_orders;
ALTER TABLE fact_orders_new RENAME TO fact_orders;Cần cẩn thận với quyền, view phụ thuộc và thời điểm đổi tên.
Vì sao INSERT gây trùng
INSERT INTO fact_orders
SELECT * FROM staging_orders WHERE order_date = '2026-03-01';Chạy lần đầu: 12.000 dòng. Retry: thêm 12.000 dòng nữa. Không có lỗi nào được báo — bảng chỉ đơn giản là có gấp đôi.
Đây là lỗi nguy hiểm nhất vì im lặng. Số liệu dashboard sai nhưng pipeline vẫn xanh.
Bảng tạm và kiểm tra trước khi ghi
Mẫu an toàn hơn cho dữ liệu lớn:
BEGIN;
CREATE TEMP TABLE stg AS
SELECT * FROM raw_orders WHERE order_date = '2026-03-01';
-- kiểm tra
-- SELECT COUNT(*) FROM stg; -- phải > 0
DELETE FROM fact_orders WHERE order_date = '2026-03-01';
INSERT INTO fact_orders SELECT * FROM stg;
COMMIT;Nếu số dòng bằng 0 do nguồn lỗi, dừng lại thay vì xoá sạch ngày đó. Một DELETE không có INSERT tương ứng là thảm hoạ khó phát hiện.
Kiểm tra idempotency
Chạy task hai lần cho cùng logical date, rồi so sánh:
SELECT
COUNT(*) AS so_dong,
COUNT(DISTINCT order_id) AS so_dong_khac_nhau,
SUM(amount) AS tong
FROM fact_orders
WHERE order_date = '2026-03-01';Sau lần hai, cả ba số phải giữ nguyên.
Kiểm tra bổ sung: so sánh checksum giữa hai lần chạy, hoặc đối chiếu tổng với nguồn.
Những thứ khó idempotent
| Thành phần | Vấn đề | Cách xử lý |
|---|---|---|
| Gửi email/Slack | Gửi lại nhiều lần | Ghi cờ đã gửi |
| Gọi API tính tiền | Tính hai lần | Dùng idempotency key |
| Sinh ID tự tăng | ID khác nhau mỗi lần | Dùng khoá nghiệp vụ |
| Ghi file có timestamp | Nhiều file trùng | Ghi theo partition cố định |
Với tác dụng phụ ra ngoài, idempotency không thể đảm bảo bằng SQL — cần khoá hoặc cờ trạng thái ở hệ thống đích.
Lỗi thường gặp
INSERTkhông xoá partition: trùng dữ liệu khi retry.DELETEvàINSERTngoài transaction: mất dữ liệu nếu lỗi giữa chừng.- Không kiểm tra số dòng staging: xoá sạch ngày khi nguồn rỗng.
- MERGE với khoá không duy nhất: lỗi hoặc cập nhật sai.
- Ghi file theo timestamp: không ghi đè được.
- Retry áp cho task gửi thông báo: gửi nhiều lần.
Thực hành
- Viết
DELETE+INSERTtrong một transaction. - Viết
MERGEtheoorder_id. - Chạy thử hai lần và so sánh số dòng.
- Thêm kiểm tra staging rỗng trước khi xoá.
- Liệt kê ba tác dụng phụ ngoài database cần xử lý riêng.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
| Số dòng tăng gấp đôi | INSERT thuần | Xoá partition trước |
| Ngày mất sạch dữ liệu | Lỗi giữa DELETE và INSERT | Dùng transaction |
| Tổng tiền sai sau retry | Ghi trùng | Kiểm tra khoá duy nhất |
| Email gửi hai lần | Retry task thông báo | Ghi cờ đã gửi |
| File trùng trong S3 | Tên có timestamp | Ghi theo partition |
Tóm tắt
- Idempotent nghĩa là chạy lại không đổi kết quả.
- Ba mẫu: xoá partition, MERGE, đổi bảng.
INSERTthuần là nguyên nhân phổ biến nhất gây trùng.DELETEvàINSERTphải nằm trong một transaction.- Kiểm tra bằng cách chạy hai lần và so sánh.
Dùng ← → để chuyển bài