Mục tiêu học tập
- Hệ thống hóa cơ chế retry/DLQ theo từng service trong pipeline
- Hiểu delivery semantics: at-least-once là mặc định → phải idempotent
- Nắm các kỹ thuật idempotent write theo từng data store
- Thiết kế pipeline "recover được": checkpoint, backfill, reprocess
1. Delivery semantics — sự thật nền tảng
| Semantics | Nghĩa | Thực tế AWS |
|---|---|---|
| At-most-once | Có thể mất, không trùng | Hiếm dùng cho data |
| At-least-once | Không mất, có thể trùng | Mặc định của S3 events, SQS standard, Kinesis, Lambda retry, DMS... |
| Exactly-once | Không mất, không trùng | Chỉ trong phạm vi hỗ trợ: Flink checkpoint, Kafka transactions, FIFO dedup — end-to-end phải tự thiết kế bằng idempotency |
→ Câu thần chú: "assume duplicates, design idempotent".
2. Retry và DLQ theo service (bảng tổng hợp)
| Service | Cơ chế lỗi |
|---|---|
| Lambda async (S3/SNS event) | Retry 2 lần → on-failure destination / DLQ |
| Lambda + SQS | Message quay lại queue (visibility timeout) → maxReceiveCount → SQS DLQ; partial batch response |
| Lambda + Kinesis | Retry chặn shard → cấu hình max retry, bisect batch, on-failure destination |
| Step Functions | Retry (backoff, maxAttempts) + Catch per state — trung tâm điều phối lỗi |
| Glue job | MaxRetries ở job; bookmark chỉ commit khi thành công |
| Firehose | Retry đích → S3 error/backup prefix — không mất data |
| EventBridge | Retry 24h → DLQ (SQS) per target |
| SQS | Redrive policy → DLQ; redrive ngược DLQ → source sau khi sửa |
Nguyên tắc chung: mọi điểm async đều phải có "chỗ rơi" (DLQ/error prefix) + alarm trên chỗ rơi đó.
3. Idempotency theo data store
| Store | Kỹ thuật ghi idempotent |
|---|---|
| S3 | Ghi deterministic key (cùng input → cùng path, PUT ghi đè); ghi theo partition overwrite thay vì append |
| Iceberg | MERGE INTO theo khóa — chạy lại không tạo trùng |
| Redshift | Staging table + DELETE ... USING staging rồi INSERT (upsert pattern), hoặc MERGE; không append mù |
| DynamoDB | Conditional write (attribute_not_exists), idempotency key table |
| OpenSearch | Index với document _id xác định — ghi lại là update |
| Chung | Idempotency key từ event id; bảng marker "đã xử lý" (DynamoDB + TTL) |
4. Checkpoint / restart / backfill
- Checkpoint có sẵn: Glue bookmark, KCL lease (DynamoDB), Flink checkpoint, Spark streaming checkpoint, DMS task position — hiểu mỗi cái commit lúc nào (thường: sau khi thành công → phần lỡ dở sẽ chạy lại → cần idempotent sink)
- Backfill/reprocess: thiết kế job nhận tham số dải thời gian/partition để chạy lại một khoảng (kết hợp bookmark pause); raw zone immutable là điều kiện để reprocess an toàn
- Poison record: một record hỏng không được phép giết pipeline — bisect/DLQ/quarantine rồi xử lý riêng
5. Checklist thiết kế pipeline chịu lỗi
- Mọi consumer async có DLQ/on-failure destination + alarm trên độ sâu DLQ
- Sink idempotent (theo bảng mục 3)
- Retry có backoff + jitter, có giới hạn (không retry vô hạn)
- Checkpoint đúng chỗ; hiểu semantics khi fail giữa chừng
- Job tham số hóa để backfill theo dải partition
- Timeout mọi job/step (Step Functions
TimeoutSeconds, Glue timeout) - Phân loại lỗi: transient (retry) vs permanent (DLQ ngay, đừng retry 24h)
Câu hỏi ôn tập
-
Glue job nightly fail lúc 2h sáng sau khi ghi một nửa output ra S3 (append). Chạy lại sinh dữ liệu trùng. Sửa thiết kế thế nào?
Xem đáp án
Làm sink idempotent: (1) ghi theo partition overwrite — job ghi đè toàn bộ partition ngày đó thay vì append (chạy lại = ghi đè sạch); hoặc (2) chuyển bảng Iceberg + MERGE INTO theo khóa; hoặc (3) ghi ra staging prefix, thành công mới move/commit. Kèm bookmark hiểu rằng phần fail sẽ được đọc lại (at-least-once).
-
Pipeline SQS → Lambda thỉnh thoảng có message lỗi vĩnh viễn (dữ liệu hỏng). Yêu cầu: không mất message, không nghẽn queue, có cảnh báo. Thiết kế?
Xem đáp án
Redrive policy với
maxReceiveCount(vd 3) → message hỏng sang DLQ; CloudWatch alarm trênApproximateNumberOfMessagesVisiblecủa DLQ → SNS; sau khi sửa code/dữ liệu dùng DLQ redrive đẩy ngược về queue nguồn. Kết hợp partial batch response để không retry oan message tốt cùng batch. -
Nạp incremental vào Redshift mỗi giờ, đôi khi file nguồn được gửi lại (duplicate). Pattern nạp chống trùng?
Xem đáp án
Staging + upsert: COPY vào staging table, rồi trong một transaction
DELETE FROM target USING staging WHERE khóa trùng+INSERT INTO target SELECT ... FROM staging(hoặc dùngMERGE). Chạy lại bao nhiêu lần kết quả vẫn đúng — idempotent. Append thẳng COPY vào target là nguồn gốc trùng lặp. -
Phân biệt lỗi transient và permanent — vì sao chiến lược retry phải khác nhau?
Xem đáp án
Transient (throttle, timeout mạng, service tạm lỗi): retry với exponential backoff + jitter thường tự khỏi. Permanent (dữ liệu hỏng, schema sai, AccessDenied): retry chỉ đốt tài nguyên và trì hoãn — phải fail nhanh sang DLQ/quarantine và alert. Trong Step Functions: khai báo
Retrycho ErrorEquals transient,Catchcho lỗi còn lại sang nhánh xử lý. -
Cần chạy lại pipeline cho riêng ngày 2026-07-01 do phát hiện bug transform. Điều kiện thiết kế nào giúp việc này an toàn?
Xem đáp án
(1) Raw zone immutable còn nguyên dữ liệu gốc ngày đó; (2) job tham số hóa theo partition (
--date 2026-07-01) thay vì "xử lý những gì mới"; (3) sink idempotent theo partition (overwrite/MERGE) để ghi lại không trùng; (4) bookmark ở chế độ pause hoặc đường chạy backfill riêng không phá state incremental. Thiếu các điều kiện này, backfill thành nguồn lỗi mới.
Bài tập thực hành
- Thêm DLQ + alarm cho một Lambda event source trong lab
- Viết pattern staging-upsert (SQL) cho bảng Redshift orders
- Sửa Glue job lab: nhận tham số
--process_datevà ghi overwrite partition tương ứng - Đọc Exponential backoff and jitter (AWS builders' library)
Tài liệu tham khảo chính thức
- SQS dead-letter queues
- Step Functions error handling
- Lambda event source mapping error handling
- Redshift MERGE
Tiếp theo: Quiz Tuần 6