Kiến trúc hướng sự kiện (event-driven architecture) là cách tổ chức tích hợp trong đó hệ thống phát đi thông báo "điều gì vừa xảy ra" — đơn hàng đã tạo, hàng đã xuất kho, khách đã thanh toán — và các hệ thống quan tâm tự đăng ký nhận, thay vì hệ thống nguồn phải gọi trực tiếp từng nơi. Hàng đợi thông điệp (message queue) là hạ tầng trung gian giữ các thông báo đó cho tới khi bên nhận xử lý xong.
Mô hình này đáng đầu tư khi một sự kiện cần đến nhiều nơi, khi bên nhận có thể tạm ngừng mà không được làm mất dữ liệu, hoặc khi khối lượng giao dịch dao động mạnh theo giờ cao điểm. Nó không đáng khi doanh nghiệp chỉ có vài hệ thống trao đổi theo lô cuối ngày. Cái giá phải trả là phải chấp nhận dữ liệu giữa các hệ thống nhất quán sau một độ trễ, không tức thì.
Gọi trực tiếp và phát sự kiện: hai cách nghĩ khác nhau
Trong tích hợp kiểu gọi trực tiếp, khi một đơn hàng được tạo trên website, website gọi API kho để giữ hàng, gọi API kế toán để tạo hoá đơn nháp, gọi API hệ thống email để gửi xác nhận. Website phải biết có ba bên, phải chờ từng bên trả lời, và nếu hệ thống email đang lỗi thì phải tự quyết định có huỷ đơn hay không. Thêm một bên thứ tư — chẳng hạn hệ thống tích điểm — nghĩa là phải sửa mã website.
Cách này không sai. Với hai ba bên nhận và nghiệp vụ cần biết kết quả ngay — như kiểm tra còn hàng trước khi cho khách đặt — gọi trực tiếp là lựa chọn đúng vì đơn giản, dễ gỡ lỗi và trả lời được ngay. Vấn đề chỉ xuất hiện khi số bên nhận tăng và một bên chậm hoặc lỗi kéo cả chuỗi chậm theo: khách bấm đặt hàng phải chờ cả hệ thống email phản hồi mới thấy trang xác nhận.
Trong mô hình hướng sự kiện, website chỉ làm một việc: ghi nhận đơn và phát sự kiện "đơn hàng đã tạo" kèm dữ liệu cần thiết lên một kênh. Kho, kế toán, email, tích điểm mỗi bên tự lắng nghe kênh đó và xử lý theo nhịp của mình. Website không cần biết ai đang nghe. Thêm bên mới chỉ là thêm một người đăng ký, không chạm vào hệ thống nguồn.
Sự đảo chiều trách nhiệm này gọi là tách rời (decoupling) theo ba nghĩa: tách về không gian (không cần biết địa chỉ của nhau), tách về thời gian (bên nhận không cần đang chạy lúc sự kiện phát ra), và tách về tốc độ (bên nhận chậm không làm bên gửi chậm theo). Đó là lý do mô hình này phổ biến ở thương mại điện tử, ngân hàng, logistics — những nơi một giao dịch kích hoạt nhiều quy trình hạ nguồn.
Hàng đợi điểm–điểm và mô hình xuất bản–đăng ký
Hai mô hình phân phối thông điệp cơ bản thường được dùng kết hợp. Hiểu khác biệt giúp đọc đúng đề xuất kỹ thuật của nhà thầu.
| Đặc điểm | Hàng đợi (queue) | Xuất bản–đăng ký (pub/sub) |
|---|---|---|
| Số bên nhận mỗi thông điệp | Một bên trong nhóm xử lý nhận và xử lý | Mọi bên đăng ký đều nhận một bản |
| Mục đích điển hình | Phân chia công việc, ví dụ nhiều tiến trình cùng xử lý hàng đợi đơn cần in phiếu | Thông báo một sự kiện cho nhiều hệ thống quan tâm |
| Sau khi xử lý | Thông điệp bị xoá khỏi hàng đợi | Tuỳ nền tảng: xoá sau khi mọi bên nhận, hoặc lưu theo thời hạn để đọc lại |
| Thêm bên nhận mới | Chia sẻ tải với các bên hiện có | Nhận thêm một luồng độc lập, không ảnh hưởng bên khác |
| Ví dụ công cụ | Các hệ thống hàng đợi thông điệp truyền thống, dịch vụ hàng đợi của các nhà cung cấp đám mây | Các nền tảng nhật ký sự kiện phân tán như Apache Kafka, dịch vụ chủ đề trên đám mây |
Apache Kafka, do LinkedIn phát triển và mở mã nguồn năm 2011, phổ biến hoá ý tưởng lưu sự kiện thành một nhật ký chỉ ghi thêm, cho phép bên nhận đọc lại từ một thời điểm trong quá khứ. Khả năng đọc lại này hữu ích khi một hệ thống mới tham gia và cần dựng lại trạng thái từ lịch sử, hoặc khi phải xử lý lại sau khi sửa lỗi.
Bảo đảm giao nhận: vì sao "đúng một lần" khó đến vậy
Câu hỏi đầu tiên nhà quản lý nên đặt cho bất kỳ thiết kế tích hợp nào: nếu mạng đứt giữa chừng, thông điệp có bị mất không, có bị xử lý hai lần không? Các nền tảng thông điệp thường mô tả ba mức bảo đảm. Nhiều nhất một lần: có thể mất, không bao giờ trùng — chấp nhận được cho dữ liệu đo lường không quan trọng. Ít nhất một lần: không mất, nhưng có thể trùng — mức phổ biến nhất trong thực tế. Đúng một lần: lý tưởng, nhưng trong hệ phân tán chỉ đạt được trong những phạm vi giới hạn và với chi phí cao.
Lý do sâu xa nằm ở bản chất mạng: bên gửi không thể phân biệt "bên nhận chưa nhận được" với "bên nhận đã nhận nhưng xác nhận bị mất trên đường về". Để không mất dữ liệu, bên gửi phải gửi lại, và do đó bên nhận có thể nhận trùng. Đây là một giới hạn lý thuyết của hệ phân tán, không phải khuyết điểm của một sản phẩm cụ thể.
Hệ quả thiết kế: bên nhận phải idempotent, tức xử lý cùng một thông điệp nhiều lần cho cùng kết quả như một lần. Cách làm phổ biến là mỗi sự kiện mang một mã duy nhất, bên nhận lưu danh sách mã đã xử lý và bỏ qua mã lặp. Với kế toán, đây là ranh giới giữa một hoá đơn và hai hoá đơn cho cùng một đơn hàng.
Mẫu outbox và hàng đợi thư lỗi: hai kỹ thuật nên biết tên
Một lỗi tinh vi hay gặp: hệ thống ghi đơn hàng vào cơ sở dữ liệu thành công, rồi phát sự kiện thì thất bại — hoặc ngược lại, phát sự kiện rồi mới ghi thì ghi lỗi. Kết quả là kho nhận thông báo về một đơn không tồn tại, hoặc đơn tồn tại mà không ai được báo. Mẫu outbox (transactional outbox) giải quyết bằng cách ghi sự kiện vào một bảng "hộp thư đi" trong cùng giao dịch cơ sở dữ liệu với đơn hàng; một tiến trình riêng đọc bảng này và phát sự kiện, thử lại cho tới khi thành công. Hai việc hoặc cùng xảy ra, hoặc cùng không.
Hàng đợi thư lỗi (dead letter queue) là nơi chứa các thông điệp bên nhận đã thử xử lý nhiều lần mà vẫn thất bại, ví dụ đơn có mã sản phẩm không tồn tại trong kho. Thay vì chặn cả hàng đợi hoặc âm thầm bỏ qua, thông điệp lỗi được tách ra để người phụ trách xem, sửa nguyên nhân và gửi lại. Mẫu này có trong danh mục của Hohpe và Woolf từ năm 2003 và vẫn là thành phần bắt buộc của mọi thiết kế tích hợp nghiêm túc.
Khi duyệt thiết kế, hãy hỏi nhà thầu hai câu: sự kiện được phát trong cùng giao dịch với dữ liệu nghiệp vụ hay không, và ai nhận cảnh báo khi hàng đợi thư lỗi có thông điệp mới. Câu trả lời mơ hồ ở một trong hai câu là dấu hiệu thiết kế chưa tính đến trường hợp lỗi.
Nhất quán cuối cùng: cái giá nghiệp vụ phải chấp nhận
Khi các hệ thống cập nhật theo sự kiện bất đồng bộ, có một khoảng thời gian — thường vài trăm mili giây đến vài giây, có khi lâu hơn nếu bên nhận đang bảo trì — trong đó các hệ thống chưa thống nhất. Đơn đã tạo trên website nhưng tồn kho chưa trừ; khách đã thanh toán nhưng CRM vẫn hiện chưa thanh toán. Trạng thái này gọi là nhất quán cuối cùng (eventual consistency): nếu không có thay đổi mới, mọi bản sao sẽ hội tụ về cùng giá trị.
Lý thuyết nền là định lý CAP do Eric Brewer nêu năm 2000 và được Gilbert và Lynch chứng minh hình thức năm 2002: khi mạng bị phân mảnh, hệ phân tán phải chọn giữa nhất quán tức thì và luôn sẵn sàng phục vụ. Diễn giải thực dụng cho doanh nghiệp là: muốn các hệ thống độc lập và chịu lỗi tốt, phải thiết kế nghiệp vụ chịu được độ trễ.
Điều này đòi hỏi quyết định nghiệp vụ cụ thể. Bán quá tồn kho trong vài giây trễ có chấp nhận được không, và nếu xảy ra thì xử lý thế nào — huỷ đơn, đặt hàng bổ sung, hay giữ một lượng tồn đệm? Giao diện có cần hiện trạng thái "đang xử lý" thay vì khẳng định ngay? Những nghiệp vụ không chịu được độ trễ, như trừ tiền trong ví hay cấp số hoá đơn liên tục, nên giữ trong một hệ thống với giao dịch nguyên tử thay vì rải qua nhiều dịch vụ.
Khi nào nên và không nên dùng kiến trúc hướng sự kiện
Danh sách dưới đây giúp sàng lọc nhanh trước khi đi vào thiết kế chi tiết.
- Nên dùng khi một sự kiện cần kích hoạt từ ba hệ thống hạ nguồn trở lên và danh sách này còn tăng.
- Nên dùng khi khối lượng biến động mạnh, ví dụ đợt khuyến mãi làm đơn hàng tăng gấp nhiều lần trong vài giờ, cần hàng đợi để hấp thụ đỉnh.
- Nên dùng khi bên nhận không ổn định hoặc có lịch bảo trì riêng mà không được làm mất dữ liệu.
- Nên dùng khi cần lưu vết đầy đủ chuỗi sự kiện để kiểm toán hoặc phân tích hành vi.
- Chưa nên khi chỉ có hai ba hệ thống trao đổi theo lô cuối ngày; tích hợp theo lịch đơn giản và dễ đối chiếu hơn.
- Chưa nên khi đội ngũ chưa có người vận hành được nền tảng thông điệp và giám sát độ trễ, hàng đợi lỗi.
- Chưa nên cho nghiệp vụ đòi nhất quán tức thì tuyệt đối mà không có phương án bù trừ khi lệch.
Cách tiếp cận thận trọng là bắt đầu với một luồng sự kiện có giá trị rõ, như đồng bộ tồn kho từ kho trung tâm ra các kênh bán, dùng dịch vụ hàng đợi được nhà cung cấp đám mây quản lý để không phải tự vận hành hạ tầng, rồi mở rộng khi đội ngũ đã quen với cách giám sát và xử lý lỗi.
Câu hỏi thường gặp
Webhook có phải là kiến trúc hướng sự kiện không?
Webhook là một cách phát sự kiện đơn giản: hệ thống nguồn gọi thẳng sang địa chỉ của bên nhận khi có thay đổi. Nó mang tinh thần hướng sự kiện nhưng thiếu hàng đợi trung gian, nên nếu bên nhận ngừng hoạt động lâu, sự kiện có thể mất sau vài lần thử lại. Nhiều hệ thống nhận webhook rồi đẩy ngay vào hàng đợi nội bộ để xử lý an toàn.
Kiến trúc hướng sự kiện có làm hệ thống chậm hơn không?
Thời gian từ khi sự kiện xảy ra đến khi mọi bên cập nhật có thể dài hơn gọi trực tiếp một chút, nhưng hệ thống nguồn phản hồi người dùng nhanh hơn vì không phải chờ các bên hạ nguồn. Ở giờ cao điểm, hàng đợi giúp hệ thống không bị sập mà chỉ xử lý chậm lại.
Thứ tự sự kiện có được bảo đảm không?
Không phải lúc nào cũng vậy. Nhiều nền tảng chỉ bảo đảm thứ tự trong một phân vùng hoặc một khoá, ví dụ mọi sự kiện của cùng một đơn hàng. Nếu nghiệp vụ phụ thuộc thứ tự, như "tạo đơn" phải đến trước "huỷ đơn", thiết kế phải chọn khoá phân vùng phù hợp hoặc để bên nhận tự kiểm tra số phiên bản.
Sự kiện nên chứa toàn bộ dữ liệu hay chỉ mã định danh?
Cả hai cách đều phổ biến. Sự kiện chứa đủ dữ liệu giúp bên nhận không phải gọi ngược, giảm phụ thuộc, nhưng làm thông điệp lớn và dễ lộ dữ liệu không cần thiết. Sự kiện chỉ chứa mã gọn hơn nhưng buộc bên nhận gọi API lấy chi tiết. Nhiều thiết kế chọn mức giữa: chứa các trường mà phần lớn bên nhận cần.
Ai quản lý định dạng sự kiện khi nhiều bên cùng dùng?
Cần một danh mục lược đồ sự kiện có phiên bản, giống hợp đồng API. Bên phát sự kiện chịu trách nhiệm giữ tương thích ngược, chỉ thêm trường mới chứ không đổi nghĩa hay xoá trường cũ khi chưa thông báo. Thiếu quy tắc này, một thay đổi nhỏ ở nguồn có thể làm hỏng nhiều hệ thống nhận cùng lúc.
Doanh nghiệp vừa có cần tự vận hành Kafka không?
Thường không cần. Các dịch vụ hàng đợi và chủ đề do nhà cung cấp đám mây quản lý, hoặc tính năng hàng đợi có sẵn trong iPaaS, đủ cho khối lượng của phần lớn doanh nghiệp vừa. Tự vận hành nền tảng nhật ký sự kiện phân tán đòi hỏi kỹ năng chuyên sâu về vận hành và giám sát.