Kiến trúc Hướng sự kiện (EDA) và SEDA
Mở rộng hành vi thông qua Kiến trúc Hướng sự kiện (EDA), 4 mô hình truyền thông điệp, chiến lược cân bằng tải L4/L7, 4 mô hình đồng thời và cấu trúc Staged Event-Driven Architecture (SEDA).
Mở rộng Hành vi (Scaling Behavior) và Kiến trúc EDA
Trong khi mở rộng trạng thái (Scaling State) tập trung vào độ bền vững và phân vùng dữ liệu, thì Mở rộng Hành vi (Scaling Behavior) tập trung vào việc thiết kế các dịch vụ có kết nối lỏng lẻo (loose coupling) và luồng thực thi không chặn (non-blocking).
Kiến trúc Hướng sự kiện (Event-Driven Architecture - EDA) xây dựng trên bốn trụ cột:
- Events (Sự kiện): Đại diện cho một sự thật bất biến đã xảy ra trong quá khứ (ví dụ
OrderCreated,PaymentReceived). - Messaging (Truyền thông điệp): Giao tiếp qua hàng đợi hoặc kênh trung gian thay vì gọi hàm trực tiếp.
- Asynchronous (Bất đồng bộ): Bên gửi không chờ đợi bên nhận xử lý xong.
- Non-blocking (Không chặn): "Đừng chờ đợi, hãy chuyển sang làm việc khác và không bao giờ khóa luồng" (Never block).
EDA thường kết hợp hoàn hảo với hai mẫu thiết kế: Event Sourcing (lưu trữ toàn bộ biến động nghiệp vụ dưới dạng chuỗi sự kiện nối tiếp) và CQRS (tách biệt hoàn toàn mô hình ghi nhận lệnh - Command khỏi mô hình truy vấn dữ liệu - Query).
Bốn Mẫu Truyền Thông điệp Chuẩn mực
Tầng hạ tầng thông điệp (RabbitMQ, Apache Kafka, ActiveMQ) sử dụng bốn mẫu truyền phát chuẩn:
| Mẫu Giao tiếp | Tỷ lệ | Nguyên lý Hoạt động | Ứng dụng Điển hình |
|---|---|---|---|
| 1. Publish-Subscribe | 1 : N | Publisher đẩy tin vào Topic; toàn bộ N bên đăng ký (Subscribers) đều nhận được bản sao. | Thông báo đẩy (Notification), luồng sự kiện phân tích (Analytics), Audit logging. |
| 2. Queuing (Point-to-Point) | 1 : 1 | Tin nhắn được gửi vào Queue; mỗi tin chỉ có 1 Worker tiêu thụ xử lý. | Chia tải công việc giữa các tiến trình Worker nền (Xử lý ảnh, xuất báo cáo). |
| 3. Request-Reply | 1 : 1 | Giao tiếp hai chiều bất đồng bộ; client gửi tin kèm reply_to queue để nhận kết quả. | Tích hợp RPC bất đồng bộ giữa các microservices. |
| 4. Store and Forward | 1 : 1 | Hệ thống ghi tin nhắn bền vững xuống ổ đĩa trước khi truyền qua mạng tới đích. | Đảm bảo không mất dữ liệu giao dịch tài chính khi mạng bị gián đoạn. |
Kiến trúc Hướng sự kiện Phân tầng (SEDA)
Trong mô hình máy chủ truyền thống (JEE, Apache Tomcat), mỗi kết nối người dùng được gán một luồng riêng biệt (thread-per-request). Mô hình này sụp đổ nhanh chóng khi có hàng chục nghìn kết nối đồng thời do chi phí chuyển ngữ cảnh (context switching) và cạn kiệt bộ nhớ stack.
SEDA (Staged Event-Driven Architecture) do Matt Welsh đề xuất đã phân rã toàn bộ ứng dụng thành một đồ thị các Giai đoạn (Stages) độc lập:
- Incoming Event Queue (Hàng đợi có giới hạn): Đóng vai trò vùng đệm làm mượt lưu lượng và áp đặt kiểm soát thu nhận (Admission Control). Khi hàng đợi đầy, hệ thống tự động từ chối hoặc áp dụng Backpressure.
- Event Handler: Thực thi logic nghiệp vụ không chặn cho từng thông điệp.
- Thread Pool Cục bộ: Bể luồng được định cỡ riêng cho đặc tính I/O của Stage đó (ví dụ Stage đọc đĩa có số luồng khác Stage tính toán CPU).
- Dynamic Controller: Tự động điều chỉnh kích thước thread pool, tham số gom lô (batching) dựa trên độ dài hàng đợi và thời gian đáp ứng thời gian thực.
Chiến lược Cân bằng Tải (Load Balancing)
Bộ cân bằng tải đóng vai trò phân phối lưu lượng tới cụm máy chủ phi trạng thái. Hệ thống phân chia thành hai tầng:
- Layer 4 (L4): Định tuyến cực nhanh ở tầng TCP/UDP dựa trên IP và Port mà không giải mã nội dung gói tin (HAProxy, IPVS).
- Layer 7 (L7): Hiểu ngữ nghĩa giao thức HTTP, định tuyến thông minh dựa trên URL path, Header, Cookie (Nginx, Envoy, ALB).
Độ trễ Đuôi Trung bình (ms) theo 5 Thuật toán Điều phối Tải dưới Áp lực Cao:
Bốn Mô hình Lập trình Đồng thời & Mô hình Actor
Jonas Bonér phân tích bốn mô hình đồng thời: Shared-State (khóa đồng bộ, dễ deadlock), Dataflow Concurrency (không có tính bất định, luồng dữ liệu tự đánh thức), Software Transactional Memory - STM (giao dịch bộ nhớ lạc quan ACI), và Message-Passing (Actor Model).
Trong Mô hình Actor (Erlang, Akka), mỗi Actor là một thực thể độc lập tuyệt đối tuân thủ nguyên lý Share Nothing:
# Minh họa Mô hình Actor (Share Nothing)
# Mỗi Actor đóng gói trạng thái và chỉ tương tác qua Hộp thư (Mailbox)
import asyncio
class OrderActor:
def __init__(self, order_id):
self.order_id = order_id
self.state = "CREATED" # Trạng thái cô lập tuyệt đối, không chia sẻ RAM
self.mailbox = asyncio.Queue()
async def run(self):
while True:
msg = await self.mailbox.get()
action = msg.get("action")
if action == "PAY":
if self.state == "CREATED":
self.state = "PAID"
print(f"[Order {self.order_id}] Đã thanh toán! Chuyển trạng thái -> PAID")
# Gửi tin nhắn bất đồng bộ sang NotificationActor
await msg["reply_to"].put({"status": "SUCCESS", "order_id": self.order_id})
elif action == "CANCEL":
self.state = "CANCELLED"
print(f"[Order {self.order_id}] Hủy đơn hàng.")
self.mailbox.task_done()Các Trang Liên quan
- Nền tảng Thiết kế Hệ thống và Các Đánh đổi Cốt lõi — Động lực chuyển từ Scale Up sang Scale Out.
- Phân mảnh RDBMS, DHT và Hệ sinh thái NoSQL — Quản lý trạng thái phân tán phía sau các worker EDA.
- Các Chiến lược Bộ nhớ Đệm Phân tán — Tích hợp vô hiệu hóa cache theo sự kiện.
- Các Mẫu Thiết kế Độ Ổn định Hệ thống — Áp dụng Throttling, Backpressure và Let-It-Crash cho kiến trúc Actor/SEDA.