---
title: "Thiết kế hệ thống event-driven - message queue, pub/sub, saga, CQRS và event sourcing"
description: "Khóa học thiết kế hệ thống event-driven tập trung vào cách consumer đọc dữ liệu qua broker. Bạn sẽ nắm vững kỹ thuật chọn partition key, xử lý poison message, thiết kế saga, replay và xác định khi nào cần CQRS hay event sourcing. Kiến trúc của bạn sẽ mở rộng bền vững mà không bị nghẽn bởi các lời gọi đồng bộ."
canonical: "https://200lab.io/courses/thiet-ke-he-thong-event-driven-message-queue-pub-sub-saga-cqrs-va-event-sourcing"
type: "course"
course_type: "course"
learning_type: "free_form"
published: "2026-10-06T15:07:50Z"
students: 73
---

## Khóa học này mang lại gì cho bạn

Khi hệ thống phát triển, việc gọi HTTP đồng bộ hoặc đẩy chung mọi tác vụ vào một hàng đợi đơn giản sẽ bộc lộ nhiều giới hạn. Thêm consumer mới khiến producer phải sửa đổi và deploy lại, các lời gọi phụ làm chậm luồng xử lý chính, và dữ liệu giữa các dịch vụ bắt đầu xuất hiện độ lệch. Bảy năng lực thực tế dưới đây giúp bạn làm chủ luồng truyền nhận sự kiện, kiểm soát độ lệch và giữ đúng các invariant trong khi dữ liệu dẫn xuất được cập nhật bất đồng bộ:

- **Phân biệt event và command** — để chọn đúng giữa queue, pub/sub hay event log theo cách đọc của từng consumer, giúp bạn thêm dịch vụ tiêu thụ mới mà không phải sửa hay deploy lại producer.
- **Thiết kế payload của event** — với đầy đủ version và trạng thái tại thời điểm phát sinh, giúp consumer tự cập nhật dữ liệu dẫn xuất mà không cần gọi ngược về service gốc.
- **Kiểm soát thứ tự và độ trễ** — bằng cách chọn partition key phù hợp theo phạm vi bất biến, áp dụng version guard để chặn event đến muộn ghi đè trạng thái mới hơn và tính toán số partition đủ cho giờ cao điểm.
- **Xử lý sự cố và cô lập lỗi** — bằng cách phân loại lỗi tạm thời để retry có kiểm soát, chuyển poison message sang dead letter queue nhằm tránh nghẽn phân vùng và cấu hình retention đáp ứng thời gian dừng tối đa của consumer.
- **Điều phối luồng nghiệp vụ liên service** — bằng cách lựa chọn chính xác giữa choreography và orchestration, cài đặt compensation khi có bước hỏng và gắn correlation ID xuyên suốt để lần vết vòng lặp.
- **Replay và tiến hóa schema an toàn** — bằng cách dùng consumer group mới ghi sang bảng riêng, kiểm soát tính tương thích qua AsyncAPI và schema registry, kết hợp upcaster để đọc đúng các event lịch sử.
- **Xác định ranh giới kiến trúc dữ liệu** — giữa CRUD kèm audit log, CQRS và event sourcing cho từng bài toán nghiệp vụ, áp dụng expected version và snapshot khi chuỗi event đóng vai trò là nguồn sự thật duy nhất.

Khóa học tập trung vào các nguyên lý kiến trúc cốt lõi và cơ chế vận hành độc lập công nghệ, sử dụng TypeScript minh họa các mẫu thiết kế thực tế trên hệ thống phân tán.

## Khóa học cung cấp những nền tảng nào

Toàn bộ khóa học được xây dựng xoay quanh khái niệm **event** — một thông báo về sự việc đã diễn ra trong quá khứ, được producer ghi nhận một lần và phân phối tới các bên quan tâm mà không cần biết trước danh tính của consumer. Mô hình này giải phóng sự phụ thuộc giữa các dịch vụ, nhưng đòi hỏi kỹ sư phải nắm vững các dạng kiến trúc hướng sự kiện theo phân tích của [Martin Fowler](https://martinfowler.com/articles/201701-event-driven.html), cách tổ chức luồng dữ liệu thời gian thực dựa trên nhật ký phân tán từ [LinkedIn Engineering](https://web.archive.org/web/20240105095933/https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying), cũng như ranh giới thực tế khi áp dụng mô hình [CQRS](https://martinfowler.com/bliki/CQRS.html). Sáu nhóm nội dung dưới đây dẫn dắt bạn đi từ cách giao tiếp bất đồng bộ cơ bản tới việc làm chủ một event store hoàn chỉnh.

### 1. Chọn queue, pub/sub hay event log theo cách đọc của consumer

Nhóm mở đầu thiết lập nền tảng kỹ thuật thông qua việc phân biệt rõ ranh giới giữa một event và một command. Bạn sẽ hiểu vì sao việc chia sẻ chung một hàng đợi khiến hai service vô tình chia nhỏ dữ liệu của nhau, và khi nào cần cấp riêng subscription hoặc phân làn theo consumer group. Nội dung đi sâu vào cơ chế Transactional Outbox để đảm bảo tính nhất quán giữa thao tác ghi database với việc publish message, đồng thời trình bày giải pháp dùng chính bảng Postgres làm event log mà không bỏ sót các event từ transaction commit muộn. Cuối cùng, bạn sẽ nắm được phương pháp thiết kế envelope và payload để consumer tự xử lý mà không phải gọi ngược về producer.

### 2. Partition key, consumer group, lag và poison message

Nhóm thứ hai giải quyết các bài toán về hiệu năng và thứ tự xử lý khi hệ thống mở rộng quy mô tiêu thụ song song. Bạn sẽ học cách chọn partition key dựa trên phạm vi bất biến của dữ liệu, kết hợp cơ chế so sánh version tại consumer để ngăn chặn các message đến muộn ghi đè dữ liệu mới. Nhóm làm rõ giới hạn xử lý song song của một consumer group, cung cấp công thức tính số lượng partition dựa trên tải giờ cao điểm và khoảng thời gian dừng đọc do rebalance. Bạn cũng sẽ nắm vững kỹ thuật phân loại lỗi để retry có giới hạn, đẩy poison message sang dead letter queue có kiểm soát, cấu hình retention tránh mất dữ liệu và áp dụng token bucket để bảo vệ hạn mức gọi service bên ngoài.

### 3. Luồng nghiệp vụ nhiều bước chạy qua nhiều service bằng event

Nhóm thứ ba tập trung vào các luồng nghiệp vụ phức tạp kéo dài qua nhiều biên giới dịch vụ độc lập. Bạn sẽ so sánh chi tiết ưu nhược điểm giữa mô hình choreography tự phản ứng và mô hình orchestration có dịch vụ điều phối trung tâm để đưa ra quyết định phù hợp cho từng bài toán. Nhóm hướng dẫn cách thiết lập state machine lưu trạng thái luồng trong database, cài đặt các bước hoàn tác (compensation) khi có sự cố xảy ra và phân định ranh giới giữa bước có thể hủy với bước chốt (pivot step). Ngoài ra, bạn sẽ học cách gắn các định danh correlation ID, causation ID và độ sâu chuỗi vào envelope để phát hiện, ngắt bỏ các vòng lặp event vô tận.

### 4. Replay event cũ theo đúng schema lúc event được ghi

Nhóm thứ tư cung cấp các kỹ thuật vận hành và tiến hóa hệ thống theo thời gian mà không làm gián đoạn các dịch vụ đang chạy. Bạn sẽ thực hành quy trình replay dữ liệu từ log vào một bảng riêng bằng consumer group mới, đối chiếu tính chính xác của dữ liệu trước khi chuyển đổi view truy vấn. Nội dung hướng dẫn cách quản lý hợp đồng dữ liệu qua AsyncAPI, thiết lập chế độ tương thích trong schema registry và phân định thứ tự deploy an toàn giữa producer và consumer. Bạn cũng sẽ làm chủ kỹ thuật viết upcaster để chuyển đổi schema cũ sang schema mới trong bộ nhớ, xử lý bài toán xóa dữ liệu cá nhân bằng crypto-shredding và quy trình nạp lại vector khi thay đổi embedding model trong hệ thống RAG.

### 5. Đếm event cho đúng khi event đến muộn hoặc bị gửi trùng

Nhóm thứ năm xử lý các thách thức đặc thù trong việc tổng hợp số liệu từ các dòng sự kiện phân tán. Bạn sẽ phân biệt rõ ba mốc thời gian gồm event time, ingestion time, processing time và nắm được cách gom nhóm dữ liệu theo thời điểm sự việc thực sự diễn ra. Nhóm hướng dẫn kỹ thuật chốt cửa sổ thời gian dựa trên tiến độ đọc của từng partition, ghi nhận các event đến muộn thành dòng điều chỉnh và quản lý bảng chống trùng theo tiến độ tiêu thụ thay vì đồng hồ hệ thống. Bên cạnh đó, bạn sẽ biết cách áp dụng cấu trúc HyperLogLog để đếm xấp xỉ hàng triệu người dùng với dung lượng bộ nhớ cố định, đồng thời xác định các trường hợp liên quan tới tài chính bắt buộc phải đếm chính xác.

### 6. CQRS, event sourcing và khi nào CRUD là đủ

Nhóm kết thúc cung cấp khung đánh giá thực tế để lựa chọn mô hình lưu trữ tối ưu cho từng dịch vụ cụ thể. Bạn sẽ dựa trên năm tiêu chí đo lường để nhận biết khi nào một mô hình CRUD truyền thống kết hợp audit log là đủ, tránh việc phức tạp hóa hạ tầng không cần thiết. Với các dịch vụ đòi hỏi lịch sử thay đổi làm nguồn sự thật duy nhất, bạn sẽ học cách xây dựng event store trên Postgres, sử dụng expected version để chặn xung đột khi nhiều command cùng ghi vào một aggregate. Nhóm cũng hướng dẫn cách tối ưu thời gian nạp aggregate bằng snapshot theo chu kỳ và phương pháp tiến hóa cấu trúc event store mà không vi phạm nguyên tắc bất biến của dữ liệu quá khứ.

## Vì sao 200Lab tạo ra khóa học này

Trong các hệ thống phân tán, khi các dịch vụ cần phối hợp với nhau, phản xạ ban đầu của nhiều đội ngũ là thực hiện các lời gọi HTTP nối tiếp hoặc đẩy tác vụ vào một hàng đợi chung. Đến khi số lượng dịch vụ tiêu thụ tăng lên, producer bắt đầu bị kéo theo các yêu cầu thay đổi logic của hạ nguồn, hoặc các dịch vụ tiêu thụ vô tình tranh chấp và lấy mất dữ liệu của nhau. Nghiêm trọng hơn, request tạo đơn hàng chính bị chậm dần và sụt giảm độ sẵn sàng chỉ vì phải đứng chờ phản hồi từ các hệ thống phụ trợ.

Thách thức lớn nhất của kiến trúc event-driven nằm ở chỗ hệ thống thường hỏng hóc trong âm thầm mà không hề có ngoại lệ hay cảnh báo lỗi. Log app vẫn sạch sẽ, chỉ số lỗi bằng không, nhưng hóa đơn bị thiếu một nửa, trạng thái đơn hàng bị nhảy lùi, hoặc hàng trăm nghìn sự kiện biến mất do vượt quá thời gian lưu trữ của broker. Những sai lệch này chỉ được phát hiện khi đối soát dữ liệu cuối tháng hoặc khi khách hàng gửi khiếu nại về tài khoản.

Khóa học phân tích các tình huống bế tắc thường gặp khi xử lý dữ liệu sai lệch sau các đợt phát hành tính năng: ghi đè dữ liệu cũ khi replay, gửi trùng hàng loạt email cảnh báo tới đối tác, hoặc áp dụng các mẫu thiết kế phức tạp như CQRS và event sourcing vào những nơi chỉ cần một bảng dữ liệu CRUD thông thường. Việc thiếu các quy tắc kỹ thuật cụ thể về kiểm soát version, trật tự partition và ranh giới bất biến khiến hệ thống trở nên mong manh trước tải cao điểm.

Khóa học này được 200Lab thiết kế nhằm trang bị cho bạn các giải pháp kỹ thuật đã được kiểm chứng để giải quyết triệt để các vấn đề trên. Thay vì tiếp cận theo hướng cấu hình một công cụ cụ thể, bạn sẽ học cách tư duy từ triệu chứng vận hành, hiểu rõ bản chất của các cơ chế truyền nhận và tự tin đưa ra các quyết định đánh đổi kiến trúc phù hợp với quy mô thực tế của hệ thống.

## Những vấn đề thường gặp khi thiết kế hệ thống event-driven

Khi số liệu giữa các dịch vụ bị lệch, kỹ sư thường có xu hướng tìm lỗi ở các câu truy vấn database hoặc logic xử lý nội bộ của hàm. Tuy nhiên trong môi trường hướng sự kiện, nguyên nhân gốc rễ hầu như bắt nguồn từ việc hiểu sai cơ chế giao nhận của broker, sự đảo lộn thứ tự message hoặc việc đọc lại các schema cũ không đúng cách:

- Hai service đọc chung một queue làm một nửa số đơn hàng không được xuất hóa đơn dù hệ thống không có log lỗi — queue hoạt động theo cơ chế cạnh tranh giữa các worker để chia việc, muốn nhiều service cùng nhận đủ dữ liệu bắt buộc phải dùng topic với subscription hoặc consumer group riêng biệt.
- Consumer đọc bảng event theo id tăng dần làm thất thoát phí hoa hồng của hàng trăm đơn hàng — các transaction commit muộn có thể nhận id nhỏ hơn mốc đọc hiện tại của cursor, khiến các lượt quét kế tiếp bỏ qua hoàn toàn các dòng dữ liệu này.
- Tăng gấp đôi số lượng instance của consumer group nhưng throughput không tăng và lag tiếp tục dồn ứ — số lượng instance hoạt động đồng thời bị chặn bởi số lượng partition của topic, các instance vượt quá giới hạn sẽ rơi vào trạng thái nhàn rỗi.
- Trạng thái đơn hàng trên app bị nhảy lùi về bước trước sau khi đã chuyển sang bước tiếp theo — các sự kiện trong luồng retry đã rời khỏi thứ tự ban đầu của phân vùng, và consumer ghi đè dữ liệu mà không có cơ chế version guard.
- Cảnh báo lag trung bình vẫn ở ngưỡng an toàn trong khi một phân vùng bị tê liệt suốt nhiều giờ — một poison message gặp lỗi parse dữ liệu bị retry vô hạn đã chặn toàn bộ các message phía sau trong partition, trong khi chỉ số trung bình của toàn topic đã che lấp điểm nghẽn.
- Dữ liệu biến động kho bị mất trắng sau đợt bảo trì hệ thống dài ngày mà không hề có ngoại lệ phát sinh — thời gian dừng của consumer vượt quá thời hạn retention của broker, khiến các event cũ bị xóa tự động trước khi worker kịp đọc tới.
- Replay dữ liệu cũ để tính toán lại báo cáo làm phát sinh hàng nghìn email thông báo sai lệch tới người dùng — consumer dựng dữ liệu dẫn xuất bị ghép chung với tác vụ gây side-effect ra bên ngoài thay vì tách biệt thành các tiến trình độc lập.
- Tổng doanh thu sau khi replay bị chênh lệch đáng kể so với số liệu lịch sử đã chốt — payload của event đã thay đổi ngữ nghĩa qua các phiên bản nhưng consumer thiếu tầng upcaster để chuyển đổi dữ liệu về cấu trúc chuẩn tại thời điểm đọc.

Những sự cố điển hình này sẽ được phân tích cặn kẽ trong từng bài học nhằm giúp bạn xây dựng tư duy phòng ngừa và xử lý dứt điểm các lỗi tiềm ẩn trên hệ thống.

## Bạn sẽ học theo cách nào

- **Khởi đầu từ triệu chứng kỹ thuật thực tế** — qua các dòng log lỗi, đồ thị lag dựng đứng hoặc sự cố sai lệch dữ liệu cụ thể để bạn tiếp cận bài toán từ góc nhìn của một kỹ sư đang trực ca vận hành.
- **Mô hình hóa bằng sơ đồ và payload chuẩn** — giúp bạn nhìn rõ luồng dịch chuyển của message qua từng phân vùng, cấu trúc envelope và các trạng thái chuyển đổi của dữ liệu trong hệ thống.
- **Chốt quyết định dựa trên số liệu đo lường** — thông qua các phép tính cụ thể về băng thông, hạn mức phân vùng, thời gian replay và dung lượng lưu trữ thay vì dựa vào các phỏng đoán cảm tính.
- **Rèn luyện tư duy phản biện qua quiz tình huống** — yêu cầu bạn dự đoán chính xác thứ tự thực thi, phát hiện khoảng hở race condition và xác định kết quả dữ liệu trước khi xem giải pháp.
- **Thực hành qua demo kit và event lab độc lập** — với kit hướng dẫn coding agent dựng môi trường tái hiện lỗi để bạn tự sửa rồi đo lại, giúp kiểm chứng các giải pháp kỹ thuật trước và sau khi tối ưu.

## Khóa học dành cho ai

1. **Backend developer đã có kinh nghiệm làm việc với database và queue** — bạn muốn làm chủ kỹ thuật publish/subscribe, thiết kế schema event an toàn và bẻ gãy sự phụ thuộc giữa các dịch vụ trong hệ thống phân tán.
2. **Kỹ sư vận hành hệ thống messaging** — bạn cần nắm vững nguyên lý phân bổ partition, cơ chế cân bằng tải consumer group, cách cô lập poison message và phương pháp tính toán retention để bảo vệ hạ tầng.
3. **Kỹ sư phát triển luồng nghiệp vụ phức tạp hoặc xử lý dữ liệu** — bạn cần xây dựng các saga nhiều bước có tính nhất quán cao, thiết lập cơ chế đối soát dữ liệu và đảm bảo các pipeline tổng hợp số liệu phản ánh chính xác nguồn sự thật.
4. **Kỹ sư phần mềm cân nhắc kiến trúc CQRS và event sourcing** — bạn cần bộ tiêu chí kỹ thuật rõ ràng để đánh giá chính xác phạm vi áp dụng, tránh rơi vào bẫy lạm dụng kiến trúc khi mô hình CRUD kèm audit log đã đủ đáp ứng nghiệp vụ.

## Những điều cần lưu ý

- **Yêu cầu về kiến thức nền tảng** — khóa học giả định bạn đã có kinh nghiệm viết backend service với database quan hệ và hiểu cách đọc code TypeScript, SQL cũng như các định dạng log có cấu trúc; bạn không cần phải có kinh nghiệm chuyên sâu từ trước với một broker cụ thể vì các bài học nền tảng về queue, outbox và chống trùng đã được tích hợp sẵn.
- **Lộ trình học tập bổ trợ** — để có cái nhìn toàn diện hơn về các mảnh ghép hạ tầng liên quan, bạn nên tham khảo thêm các nội dung về ước lượng tải và partitioning trong hệ thống, xử lý timeout và reconciliation khi xảy ra sự cố mạng, cùng các kỹ thuật bảo vệ dịch vụ như rate limiting và circuit breaker; các chủ đề này đóng vai trò mở rộng cho các nguyên lý truyền nhận được trình bày trong khóa.
- **Phạm vi nội dung và ranh giới kỹ thuật** — chương trình tập trung vào tư duy thiết kế kiến trúc, mô hình truyền nhận và các giải pháp cấp mã nguồn thay vì hướng dẫn chi tiết việc cài đặt cụm server, quản trị cluster hay cấu hình phần cứng chuyên sâu của từng sản phẩm cụ thể; điều này giúp kiến thức của bạn không bị lỗi thời khi hạ tầng công nghệ thay đổi.
- **Bản chất của các số liệu minh họa** — mọi số liệu về lưu lượng truy cập, tỷ lệ lỗi và thời gian đo lường trong bài giảng được xây dựng nhằm mục đích đối chiếu và làm rõ các phép tính kỹ thuật; khi áp dụng vào thực tế, bạn cần thu thập số đo thực tế từ dashboard giám sát của hệ thống mình để đưa vào các công thức tương ứng.

## Bắt đầu từ đâu

Hành trình của bạn bắt đầu từ một tình huống rất quen thuộc trong ca trực: p99 latency của endpoint tạo đơn hàng tăng vọt lên **2,1 giây** do phải thực hiện năm lời gọi đồng bộ nối tiếp tới các dịch vụ phụ trợ. Bài học đầu tiên sẽ bóc tách chi tiết vì sao các lời gọi nối tiếp khiến thời gian chờ bị cộng dồn và availability của toàn hệ thống bị nhân giảm, đồng thời cung cấp bậc thang scale giúp bạn định vị chính xác thời điểm hệ thống của mình cần chuyển đổi sang kiến trúc hướng sự kiện.

## Chương trình

- Khi nào hệ thống cần chuyển sang event-driven (miễn phí)

### Chọn queue, pub/sub hay event log theo cách đọc của consumer

- Dùng queue để API không phải chờ những việc xử lý lâu · quiz
- Source of truth: dữ liệu nào là gốc, dữ liệu nào dựng lại được
- Ghi database và gọi service bên ngoài không nằm chung một transaction · quiz · kit cho agent
- Đã dùng queue mà mỗi lần thêm consumer vẫn phải sửa producer (miễn phí)
- Chặn consumer xử lý một message hai lần khi queue giao lại · quiz
- Hai service đọc chung một queue thì mỗi service chỉ nhận một phần message (miễn phí) · quiz · kit cho agent
- Đọc timeline của hai request chạy song song để tìm race condition (miễn phí)
- Đọc bảng event theo id khiến consumer bỏ sót event commit muộn · quiz · kit cho agent
- Chọn dữ liệu đưa vào event để consumer không phải gọi ngược về producer

### Partition key, consumer group, lag và poison message

- Chọn partition key để event của cùng một đơn được xử lý đúng thứ tự · quiz · kit cho agent
- Dùng version để chặn event đến muộn ghi đè trạng thái mới hơn · quiz · kit cho agent
- Gộp profile ẩn danh vào profile của tài khoản khi khách đăng nhập · kit cho agent
- Chọn số partition để consumer group theo kịp tải giờ cao điểm · quiz · kit cho agent
- Xử lý poison message để một event lỗi không làm kẹt cả partition · quiz · kit cho agent
- Event chưa đọc bị xóa khi consumer dừng lâu hơn retention · quiz · kit cho agent
- Dùng rate limiting để một client không làm chậm mọi người dùng khác · quiz
- OTP đến trễ trong đợt gửi notification cho hàng triệu người · kit cho agent

### Luồng nghiệp vụ nhiều bước chạy qua nhiều service bằng event

- Chọn choreography hay orchestration cho luồng nhiều bước chạy bằng event
- Lần theo chuỗi event để tìm event đã mở đầu một vòng lặp · quiz · kit cho agent
- Hoàn tác các bước đã xong khi bước sau thất bại · quiz
- Luồng đặt hàng chạy bằng event giao luôn cả đơn đã hủy vì thanh toán lỗi · kit cho agent

### Replay event cũ theo đúng schema lúc event được ghi

- Tính lại dữ liệu bị sai nhiều ngày bằng cách replay event · quiz · kit cho agent
- Giá và tồn kho trong kết quả search khác với trang sản phẩm · kit cho agent
- Đổi field trong event mà không làm hỏng consumer của team khác · quiz
- Event cũ bị đọc theo nghĩa mới khi replay · quiz · kit cho agent
- Xóa dữ liệu của một khách khỏi event log và mọi bản sao · kit cho agent
- Nạp lại tài liệu cho RAG khi đổi embedding model · kit cho agent
- Chọn broker theo cách đọc của consumer và constraint vận hành

### Đếm event cho đúng khi event đến muộn hoặc bị gửi trùng

- Đếm event theo lúc xảy ra, không theo lúc hệ thống nhận được · quiz · kit cho agent
- Đếm số người xem khác nhau mà không giữ hàng tỉ dòng · quiz
- Số click trên dashboard của người bán khác số trên hóa đơn · kit cho agent

### CQRS, event sourcing và khi nào CRUD là đủ

- Chọn CRUD kèm audit log, CQRS hay event sourcing cho từng service
- Kiểm tra expected version khi hai command cùng ghi vào một aggregate · quiz · kit cho agent
- Dùng snapshot để không phải đọc lại cả stream mỗi lần ghi event · quiz · kit cho agent
- Đổi schema của event khi event cũ trong event store không được sửa
