Giải mã Kiến trúc Hướng sự kiện (Event-Driven Architecture) trong hệ thống Microservices
Khi xây dựng các hệ thống Microservices hiện đại, việc lựa chọn cách thức giao tiếp giữa các dịch vụ là yếu tố sống còn quyết định độ bền vững của nền tảng. Bài viết này sẽ phân tích sâu về kiến trúc hướng sự kiện (EDA), so sánh với mô hình đồng bộ truyền thống và đi qua các mô hình thực tế áp dụng trong phát triển phần mềm.

Khi xây dựng các hệ thống backend phân tán hiện đại, đặc biệt là các hệ thống Microservices, một trong những quyết định thiết kế quan trọng nhất mà bạn phải đối mặt chính là cách các dịch vụ này "nói chuyện" với nhau. Nếu các dịch vụ liên kết quá chặt chẽ (tightly coupled), toàn bộ nền tảng của bạn sẽ trở nên mong manh và dễ vỡ.
Sự giao tiếp giữa các dịch vụ này được gọi là tương tác dịch vụ (service interaction). Nói chung, các tương tác này chia làm hai loại chính: đồng bộ (synchronous) và bất đồng bộ (asynchronous). Bài viết này sẽ cùng bạn khám phá kiến trúc hướng sự kiện (Event-Driven Architecture - EDA) và cách nó thay đổi cách vận hành của hệ thống.
Tương tác dịch vụ là gì?
Trong kiến trúc Microservices, nhiều dịch vụ độc lập cùng nhau hợp lực để vận hành một ứng dụng. Giao tiếp giữa chúng được gọi là tương tác dịch vụ và có thể được phân loại rộng thành 3 loại:
- Tương tác dẫn dắt bởi thời gian (Time-Driven Interaction)
- Tương tác dẫn dắt bởi yêu cầu (Request-Driven Interaction)
- Tương tác dẫn dắt bởi sự kiện (Event-Driven Interaction)
1. Tương tác dẫn dắt bởi thời gian (Đồng bộ)
Trong hệ thống dựa trên thời gian, các hành động được kích hoạt tại các khoảng thời gian cố định định sẵn. Hãy tưởng tượng nó giống như các công việc cron (cron jobs) hoặc xử lý theo lô theo lịch trình. Một dịch vụ sẽ "thức dậy", thực hiện nhiệm vụ của mình (ví dụ: tạo báo cáo hàng ngày hoặc khôi phục giới hạn token), sau đó "ngủ" trở lại.
Ví dụ: Hãy tưởng tượng bạn đang xây dựng Dịch vụ Thanh toán Lương (Payroll Service).
- Lương được xử lý một lần mỗi tháng.
- Hệ thống chạy một công việc theo lịch (cron).
- Một thông báo tín dụng lương được tạo ra.
2. Tương tác dẫn dắt bởi yêu cầu (Đồng bộ)
Đây là mô hình API truyền thống. Khi Dịch vụ A cần dữ liệu hoặc chức năng từ Dịch vụ B, nó gửi một yêu cầu trực tiếp (thường qua HTTP hoặc gRPC). Dịch vụ A sau đó phải chờ phản hồi trước khi có thể tiếp tục các thao tác tiếp theo. Mặc dù dễ implement, nhưng sự liên kết chặt chẽ có thể gây ra vấn đề. Nếu Dịch vụ B bị lỗi hoặc chậm, Dịch vụ A cũng sẽ bị ảnh hưởng theo.
Ví dụ: Giả sử người dùng đặt hàng trên nền tảng thương mại điện tử của bạn.
- Người dùng đặt hàng.
- Dịch vụ Đơn hàng (Order Service) gửi yêu cầu đến Dịch vụ Thanh toán (Payment Service) để xử lý.
- Dịch vụ Đơn hàng chờ phản hồi thanh toán.
- Sau khi thanh toán thành công, nó gọi Dịch vụ Thông báo để gửi xác nhận.
Mỗi bước đều phụ thuộc vào phản hồi của dịch vụ trước đó; nếu một dịch vụ thất bại, toàn bộ quy trình sẽ bị đình trệ, tạo nên một luồng đồng bộ (dẫn dắt bởi yêu cầu).
Mô hình Request-Driven Interaction
3. Kiến trúc Hướng sự kiện (Bất đồng bộ)
Trong Kiến trúc Hướng sự kiện (EDA), các dịch vụ giao tiếp bằng cách tạo ra và phản ứng với các sự kiện. Thay vì chủ động gọi các hàm hoặc chờ đợi các dịch vụ khác, một dịch vụ đơn giản là thông báo rằng có một điều gì đó vừa xảy ra.
- Nó liên quan đến việc phản ứng với những điều xảy ra (sự kiện), thay vì gọi trực tiếp các API/hàm.
- Các dịch vụ được tách rời (decoupled); dịch vụ sản xuất không quan tâm ai tiêu thụ sự kiện hoặc có bao nhiêu dịch vụ tiêu thụ.
- Trong EDA, các thành phần (dịch vụ) độc lập, nghĩa là chúng có thể hoạt động mà không cần giao tiếp trực tiếp (liên kết chặt) với nhau.
- Nó sử dụng mô hình thiết kế Xuất bản-Đăng ký (Publish-Subscribe) bên dưới để thực hiện giao tiếp.
Mô hình Xuất bản-Đăng ký (Publish-Subscribe) tóm tắt:
Đây là một mô hình nhắn tin trong đó người gửi (nhà xuất bản) gửi tin nhắn đến trung gian tin nhắn (message broker), trung gian này sau đó phân phối tin nhắn đến bất kỳ người nhận quan tâm nào (người đăng ký) đã đăng ký nhận những tin nhắn đó.
Ví dụ: Hãy xem xét một ứng dụng dự báo thời tiết.
- Dịch vụ Thời tiết (Publisher) đăng các bản cập nhật như nhiệt độ hoặc cảnh báo mưa.
- Tin nhắn được gửi đến message broker.
- Nhiều dịch vụ đăng ký nhận các bản cập nhật này:
- Dịch vụ Dự báo → dự đoán thời tiết tương lai.
- Dịch vụ Lịch sử → lưu trữ dữ liệu trong quá khứ.
- Dịch vụ Bản đồ → cập nhật thời tiết trên bản đồ.
Kiến trúc Hướng sự kiện
Các thành phần của kiến trúc hướng sự kiện
Có 5 thành phần chính trong một kiến trúc hướng sự kiện.
1. Sự kiện (Events): Đây là đơn vị giao tiếp cốt lõi của EDA. Một sự thay đổi trạng thái được gọi là một sự kiện. Trong kiến trúc này, mọi thứ diễn ra trong hệ thống backend của bạn đều là một sự kiện (ví dụ: người dùng đăng ký, đơn hàng được tạo...). Các sự kiện được phát ra bởi nguồn và có thể đóng gói nhiều loại thông tin.
Ví dụ: Dịch vụ Người dùng phát ra sự kiện UserRegistered. Sự kiện này được gửi đến Event Broker. Dịch vụ Email, đang đăng ký sự kiện này, nhận được nó, lấy dữ liệu người dùng và gửi email chào mừng. Dịch vụ Người dùng không gọi trực tiếp Dịch vụ Email, nó chỉ đơn giản phát ra sự kiện và tiếp tục công việc.
2. Nhà sản xuất sự kiện (Event Producers/Publishers): Là các dịch vụ chịu trách nhiệm phát ra sự kiện khi các điều kiện cụ thể xảy ra. Chúng chuyển đổi các hành động của hệ thống thành các tin nhắn được liệt kê mà các dịch vụ khác tiêu thụ.
Ví dụ: Trong hệ thống giao đồ ăn như GrabFood hoặc ShopeeFood. Điện thoại của tài xế liên tục gửi vị trí trực tiếp (tọa độ) qua websocket. Dịch vụ Quản lý Giao hàng nhận dữ liệu này, đóng vai trò là Producer và phát ra sự kiện LocationUpdated đến event broker.
3. Người tiêu thụ sự kiện (Event Consumers/Subscribers): Lắng nghe các sự kiện cụ thể và khi nhận được sự kiện đã đăng ký, dịch vụ sẽ kích hoạt một số logic nội bộ dựa trên sự kiện đó.
Ví dụ: Tiếp tục với hệ thống giao đồ ăn trên:
- Dịch vụ Quản lý Giao hàng phát các sự kiện
LocationUpdated. - Nhiều dịch vụ đăng ký sự kiện này:
- Dịch vụ Theo dõi → cập nhật vị trí trực tiếp trên ứng dụng người dùng.
- Dịch vụ Phân tích → phân tích hiệu suất giao hàng.
- Dịch vụ Nhà hàng → giám sát tiến độ giao hàng.
Các dịch vụ này đóng vai trò là Consumers, phản ứng với sự kiện và thực hiện nhiệm vụ của mình một cách độc lập.
Các thành phần trong EDA
4. Event Broker: Là dịch vụ trung gian (middleware) cho phép nhiều dịch vụ giao tiếp với nhau thông qua một dịch vụ tập trung. Nó định tuyến các sự kiện giữa các dịch vụ bằng cách chấp nhận sự kiện từ các nhà sản xuất và chuyển chúng đến người tiêu thụ đã đăng ký để nhận. Ví dụ: Kafka, RabbitMQ, Redis, EventBridge, v.v.
5. Chủ đề (Topics): Là các thành phần bên trong Event-Broker. Mỗi chủ đề chỉ chứa một loại sự kiện nhất định để phân biệt giữa các sự kiện. Nhà xuất bản cần biết chủ đề nào họ nên tạo sự kiện vào đó, trong khi người tiêu thụ có thể đăng ký một chủ đề cụ thể mà họ quan tâm.
Tại sao nên sử dụng Kiến trúc Hướng sự kiện? (Ưu điểm)
Sử dụng EDA mang lại nhiều lợi ích khi xây dựng hệ thống phân tán:
- Môi trường có khả năng mở rộng (Scalable): Các dịch vụ có thể mở rộng độc lập.
- Liên kết lỏng (Loose Coupling): Các dịch vụ không phụ thuộc trực tiếp vào nhau.
- Xử lý thời gian thực (Real-Time Processing): Các sự kiện được xử lý ngay khi chúng xảy ra.
- Cách ly lỗi (Fault Isolation): Nếu người tiêu thụ bị lỗi, các sự kiện có thể được thử lại sau từ broker.
- Hợp tác đa nhóm: Cho phép các nhóm lĩnh vực khác nhau làm việc cùng nhau.
- Kiểm tra độc lập: Dễ dàng kiểm tra vì các dịch vụ độc lập.
- Tính sẵn sàng cao: Hệ thống event broker có thể được mở rộng theo chiều ngang.
Nhược điểm của EDA:
Không có kiến trúc nào là hoàn hảo. EDA cũng có những sự đánh đổi nhất định:
- Thứ tự sự kiện: Các sự kiện có thể đến sai thứ tự.
- Cập nhật lược đồ sự kiện: Theo thời gian, cấu trúc sự kiện sẽ thay đổi, có thể làm hỏng một số người tiêu thụ.
- Gỡ lỗi (Debugging): Khó theo dõi luồng end-to-end trên các hệ thống bất đồng bộ.
- Xử lý sự kiện trễ.
Một số ứng dụng thực tế của EDA:
- Thông báo thời gian thực (Realtime Notifications).
- Trò chuyện trực tiếp (Live Chat).
- Hệ thống Đặt xe/Giao đồ ăn (Uber/Grab).
- Cơ chế ghi log thống nhất.
- Trò chơi nhiều người chơi (Multiplayer Games).
Các mô hình hướng sự kiện trong thực tế
Khi thiết kế cách sự kiện của bạn truyền dữ liệu, bạn sẽ gặp ba mô hình kiến trúc chính:
1. Mô hình Thông báo sự kiện (Event Notification Pattern)
Trong mô hình này, sự kiện được sử dụng để thông báo cho các microservice khác trong hệ thống rằng một thay đổi thú vị đã xảy ra. Sự kiện thông báo nhỏ và ngắn gọn (chứa rất ít thông tin về những gì đã thay đổi trạng thái) vì nó chỉ chứa một tham chiếu đến trạng thái đã thay đổi. Nếu người tiêu thụ cần thêm chi tiết, họ phải thực hiện cuộc gọi đồng bộ trở lại nguồn để lấy dữ liệu.
2. Chuyển trạng thái dựa trên sự kiện (Event-Carried State Transfer)
Trong mô hình kiến trúc này, sự kiện được sử dụng để truyền tải các thay đổi trạng thái giữa các dịch vụ. Thay vì dựa vào các mô hình yêu cầu/phản hồi đồng bộ, các bản cập nhật trạng thái được gửi trực tiếp bên trong thông tin sự kiện.
Ví dụ: Khác với mô hình thông báo, sự kiện này chứa toàn bộ chi tiết đơn hàng như orderId, mặt hàng, số lượng, địa chỉ giao hàng, v.v. Người tiêu thụ không cần gọi Dịch vụ Đơn hàng vì họ đã có tất cả dữ liệu cần thiết.
3. Event Sourcing
Mô hình Event Sourcing là một cách lưu trữ dữ liệu bằng cách ghi lại mọi thay đổi dưới dạng một chuỗi sự kiện, thay vì chỉ lưu trạng thái mới nhất. Event Sourcing ghi lại mọi thay đổi đơn lẻ là bất biến. Nếu xảy ra lỗi trong hệ thống, nó có thể xây dựng lại trạng thái hiện tại tại bất kỳ thời điểm nào bằng cách sử dụng các bản ghi sự kiện này.
Kết luận
Kiến trúc Hướng sự kiện không chỉ là một mẫu thiết kế. Đó là sự thay đổi mô hình tư duy trong cách các hệ thống suy nghĩ và giao tiếp. Mục tiêu không phải là loại bỏ giao tiếp đồng bộ, mà là sử dụng cách tiếp cận đúng đắn ở đúng nơi.
Hy vọng giờ đây bạn có sự hiểu biết tốt hơn về Kiến trúc Hướng sự kiện, các thành phần và loại hình của nó.



