Cấu hình Database riêng cho Query Side trên Ubuntu 24.04
Chúng ta cần tách biệt cơ sở dữ liệu cho Read Side để tối ưu hóa cấu trúc bảng theo các truy vấn, không bị ràng buộc bởi schema phức tạp của Event Store.
Mục tiêu: Cài đặt PostgreSQL 16, tạo user riêng và database dedicated cho Read Models.
Thực thi các lệnh sau để cài đặt và khởi động dịch vụ:
sudo apt update && sudo apt install -y postgresql postgresql-contrib
sudo systemctl enable postgresql
sudo systemctl start postgresql
Kết quả mong đợi: Dịch vụ PostgreSQL chạy và sẵn sàng, không báo lỗi.
Chuyển sang user postgres để tạo database và user mới:
sudo -u postgres psql -c "CREATE USER read_user WITH PASSWORD 'StrongReadPass123';"
sudo -u postgres psql -c "CREATE DATABASE read_db OWNER read_user;"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE read_db TO read_user;"
Kết quả mong đợi: Database "read_db" và user "read_user" được tạo thành công.
Verify kết quả bằng cách kết nối trực tiếp:
PGPASSWORD='StrongReadPass123' psql -h localhost -U read_user -d read_db -c "\dt"
Kết quả mong đợi: Kết nối thành công và hiển thị danh sách bảng (rỗng) hoặc thông báo không có bảng.
Thiết kế cơ chế lắng nghe Event (Event Bus/Stream)
Cài đặt và cấu hình RabbitMQ làm Event Bus
Chúng ta sử dụng RabbitMQ để đóng vai trò là Event Bus trung gian, nơi Command Side publish sự kiện và Read Side sẽ lắng nghe.
Mục tiêu: Cài đặt RabbitMQ, tạo queue và exchange để xử lý luồng sự kiện.
Thực thi lệnh cài đặt và khởi động RabbitMQ:
sudo apt install -y rabbitmq-server
sudo systemctl enable rabbitmq-server
sudo systemctl start rabbitmq-server
Kết quả mong đợi: RabbitMQ đang chạy trên port 5672.
Tạo user quản lý và cấp quyền toàn quyền cho vhost mặc định:
sudo rabbitmqctl add_user event_bus_admin SecureEventPass456
sudo rabbitmqctl set_permissions -p / event_bus_admin ".*" ".*" ".*"
sudo rabbitmqctl set_user_tags event_bus_admin administrator
Kết quả mong đợi: User "event_bus_admin" được tạo và có quyền quản lý.
Verify kết quả bằng cách kiểm tra trạng thái:
sudo rabbitmqctl status
Kết quả mong đợi: Xem thông tin phiên bản, node đang chạy và danh sách user.
Triển khai Projection để cập nhật Read Model từ Event
Xây dựng cấu trúc Read Model trong PostgreSQL
Read Model cần có cấu trúc phẳng (denormalized) để tối ưu tốc độ đọc, khác biệt hoàn toàn với cấu trúc chuỗi sự kiện (append-only) của Event Store.
Mục tiêu: Tạo bảng `orders` và `order_items` trong database `read_db` để lưu trữ trạng thái hiện tại.
Chạy script SQL sau để tạo schema Read Model:
PGPASSWORD='StrongReadPass123' psql -h localhost -U read_user -d read_db -f -
Kết quả mong đợi: Các bảng `orders` và `order_items` được tạo thành công cùng với các index.
Viết Projection Service (Python) để lắng nghe và cập nhật
Projection Service là thành phần quan trọng nhất của Read Side. Nó lắng nghe các event từ RabbitMQ, phân tích loại event và thực thi các thao tác SQL (INSERT, UPDATE, DELETE) tương ứng để đồng bộ hóa Read Model.
Mục tiêu: Tạo script Python lắng nghe queue "order-events", parse JSON event và cập nhật database.
Trước tiên, cài đặt các thư viện cần thiết (Pika cho RabbitMQ, psycopg2 cho Postgres):
pip3 install pika psycopg2-binary
Tạo file cấu hình và script projection tại đường dẫn `/app/projection/order_projection.py`:
cat > /app/projection/order_projection.py
Kết quả mong đợi: File script được tạo thành công tại `/app/projection/order_projection.py`.
Chạy script projection:
cd /app/projection && python3 order_projection.py
Kết quả mong đợi: Script chạy, in thông báo "Waiting for events" và lắng nghe queue.
Tối ưu hóa Read Model cho các truy vấn phổ biến
Thiết lập Indexing và Materialized Views
Để Read Side phản hồi nhanh chóng, chúng ta cần tối ưu hóa các truy vấn phổ biến như tìm đơn hàng theo khách hàng hoặc thống kê doanh thu.
Mục tiêu: Tạo Materialized View để tổng hợp dữ liệu và thêm Index cho các trường tìm kiếm thường xuyên.
Chạy lệnh SQL sau trong database `read_db` để tạo Materialized View:
PGPASSWORD='StrongReadPass123' psql -h localhost -U read_user -d read_db -f -
Kết quả mong đợi: Materialized View `mv_customer_order_summary` được tạo và cập nhật dữ liệu hiện có.
Verify toàn bộ luồng dữ liệu (End-to-End Verification)
Chúng ta cần kiểm tra xem Command Side (giả lập) có gửi event, Projection có nhận và cập nhật Read Model chính xác hay không.
Mục tiêu: Gửi một event mẫu vào RabbitMQ và kiểm tra kết quả trong PostgreSQL.
Tạo script giả lập gửi event (`publish_test_event.py`):
cat > /app/projection/publish_test_event.py
Chạy script gửi event (trong terminal mới, hoặc sau khi chạy projection):
cd /app/projection && python3 publish_test_event.py
Kết quả mong đợi: Script in "Event 'OrderCreated' sent..." và trên terminal đang chạy projection sẽ hiện log "Processed OrderCreated for ORD-2024-001".
Verify dữ liệu trong Read Model:
PGPASSWORD='StrongReadPass123' psql -h localhost -U read_user -d read_db -c "SELECT order_id, customer_id, status, total_amount FROM orders WHERE order_id = 'ORD-2024-001';"
Kết quả mong đợi: Trỏ về một dòng dữ liệu với `total_amount` = 26000000.00.
Verify dữ liệu chi tiết đơn hàng:
PGPASSWORD='StrongReadPass123' psql -h localhost -U read_user -d read_db -c "SELECT order_id, product_name, quantity, unit_price FROM order_items WHERE order_id = 'ORD-2024-001';"
Kết quả mong đợi: Trỏ về 2 dòng dữ liệu tương ứng với Laptop và Mouse.
Verify Materialized View:
PGPASSWORD='StrongReadPass123' psql -h localhost -U read_user -d read_db -c "SELECT * FROM mv_customer_order_summary WHERE customer_id = 'CUST-999';"
Kết quả mong đợi: Trỏ về tổng đơn hàng là 1 và tổng số tiền là 26000000.00.
Điều hướng series:
Mục lục: Series: Triển khai Database CQRS với Event Sourcing và Ubuntu 24.04
« Phần 4: Triển khai Command Side và xử lý Write Operations
Phần 6: Cấu hình Event Bus và đồng bộ hóa dữ liệu »