← Chương trước: Part 4: Đơn Giản Hóa CI/CD & Atomic Deployments | Mục lục Series | Chương tiếp theo: Part 6: Lộ Trình Chuyển Đổi (Migration Playbook) – Hợp Nhất →
Answer-first: Observability trong Modular Monolith tận dụng in-process tracing và profiling bộ nhớ giúp giảm thiểu 80% chi phí so với distributed tracing. Bài viết hướng dẫn cấu hình OpenTelemetry chuẩn hóa để theo dõi hiệu năng từng module mà không làm tăng độ trễ mạng.
Part 5: Observability Trong Bộ Nhớ – Khi Mọi Thứ Nằm Chung Một Call Stack
Khi nói đến vận hành hệ thống thực tế (Production), khả năng quan sát (Observability) là ranh giới giữa việc khắc phục sự cố trong 10 phút và thức trắng đêm tìm nguyên nhân. Kiến trúc Microservices đã làm cho Observability trở nên cực kỳ đắt đỏ và phức tạp với sự ra đời của Distributed Tracing (Truy vết phân tán).
Ngược lại, Modular Monolith đưa kỹ thuật gỡ lỗi trở lại cội nguồn cơ bản nhất: Giám sát toàn bộ hệ thống qua một Call Stack duy nhất trong bộ nhớ. Sự đơn giản này mang lại những ưu thế kỹ thuật rõ rệt.
1. Nỗi Đau Của Distributed Tracing
Trong kiến trúc Microservices, một request từ người dùng có thể kích hoạt chuỗi hành động đi qua 5 dịch vụ khác nhau. Để biết được yêu cầu bị nghẽn ở đâu, bạn phải sử dụng các công cụ như Jaeger, Zipkin hoặc Datadog APM để nối các log lại với nhau.
Quá trình này hoạt động dựa trên cơ chế truyền Context (Trace Propagation):
- Dịch vụ A sinh ra một
trace_id. - Dịch vụ A đóng gói
trace_idvào HTTP Header (hoặc gRPC metadata). - Dữ liệu được serialize (tuần tự hóa), mã hóa, đẩy qua mạng lưới TCP/IP.
- Dịch vụ B nhận luồng mạng, deserialize (giải mã), đọc
trace_id, tiếp tục sinh ra child span, và ghi log lại.
Hậu quả:
- Overhead hiệu năng: Việc tạo span, xử lý HTTP Header và truyền mạng làm chậm tốc độ phản hồi của mỗi dịch vụ.
- Chi phí lưu trữ phi mã: Hàng triệu dịch vụ liên tục phát thải logs và traces khiến hệ thống lưu trữ quá tải. Chi phí thu thập và index log thường xuyên cao hơn chính tiền máy chủ chạy ứng dụng (như đã đề cập ở Phần 2).
- Mất mát dữ liệu (Dropped Spans): Do đi qua mạng, nếu một dịch vụ rớt mạng hoặc log agent bị crash, bạn sẽ nhận được một Trace bị đứt đoạn, mất dấu hoàn toàn điểm lỗi thực sự.
2. Lợi Thế In-Process Của Modular Monolith và Xu Hướng 2026
Trong Modular Monolith, mọi sự giao tiếp giữa các module diễn ra trong bộ nhớ RAM (In-process memory). Khả năng quan sát (Observability) đạt hiệu quả tối đa với chi phí gần như bằng không. Đặc biệt trong giai đoạn hiện tại năm 2026, ngành công nghiệp đang chuyển dịch góc nhìn về Observability: không chỉ là việc thu thập Log/Metrics truyền thống mà được coi là một bài toán Phân tích dữ liệu hiệu năng cao (High-Performance Data Analytics). Các hệ thống lưu trữ dạng cột (Columnar Databases) như ClickHouse đang thay thế dần các giải pháp đắt đỏ cũ để hợp nhất dữ liệu giám sát một cách siêu tốc.
A. OpenTelemetry In-Process Tracing
Mặc dù OpenTelemetry được biết đến như tiêu chuẩn vàng cho Distributed Tracing, nó cũng hỗ trợ hoàn hảo cho Modular Monolith. Sự khác biệt là:
- Context propagation (truyền ID) không qua HTTP, mà được truyền qua Thread-local variables (Biến cục bộ luồng) hoặc Context object của ngôn ngữ lập trình.
- Việc tạo một Child Span mới trực tiếp trên RAM tốn khoảng vài nano giây, hoàn toàn không ảnh hưởng đến độ trễ hệ thống (so với hàng mili-giây của network parsing).
- Bạn có thể cấu hình OpenTelemetry để tạo Span mỗi khi một Module này gọi hàm của Module khác qua Internal API, giúp lập bản đồ rõ ràng ranh giới module mà không cần gánh chịu network overhead.
B. Single Call Stack và Stack Trace Tuyệt Đối
Ưu điểm lớn nhất của việc chạy trên một tiến trình duy nhất là Sự toàn vẹn của Stack Trace. Khi một Exception (Lỗi) xảy ra ở lớp Database của module Inventory (nằm sâu bên trong luồng xử lý xuất phát từ module Checkout), hệ thống Monolith sẽ in ra một Stack Trace duy nhất hiển thị chính xác toàn bộ đường đi từ Controller ngoài cùng, qua Internal API, xuống tận dòng code sinh ra lỗi. Mọi thứ liên kết hoàn hảo, đồng bộ, và đáng tin cậy 100% – điều mà Distributed Tracing không bao giờ dám bảo đảm.
C. Profiling Sâu Sát Từng Dòng Code (In-process Profiling)
Một “vũ khí bí mật” của Monolith là khả năng chạy Continuous Profiling (ví dụ dùng pprof trong Go, JFR trong Java, hay Datadog Profiler).
Thay vì chỉ biết “Service B phản hồi chậm”, Profiler có thể cho bạn biết chính xác hàm nào, vòng lặp nào, hoặc luồng (thread) nào đang chiếm dụng nhiều CPU hoặc RAM nhất trong suốt vòng đời của request. Cấp độ chi tiết đến từng dòng code này là điều bất khả thi nếu cố gắng phân tích qua các file log phân tán.
3. Khuyến Nghị Giám Sát Modular Monolith (Cập Nhật 2026)
Để thiết lập hệ thống Observability tối ưu cho Modular Monolith:
- Business-Centric Observability (SLOs theo Module): Thay vì chỉ giám sát CPU/RAM chung chung, hãy thiết lập Service Level Objectives (SLOs) riêng cho từng module (Ví dụ: “Độ trễ xử lý Module Đơn hàng < 100ms”).
- Instrument tại Biên giới Module (Tương thích Strangler Fig): Gắn OpenTelemetry span tại các public methods (Internal APIs) của mỗi module. Điều này giúp bạn tạo ra biểu đồ phụ thuộc (Dependency Graph) đẹp mắt hệt như Microservices. Nếu sau này cần bóc tách một module thành Microservice (Mẫu Strangler Fig), hạ tầng giám sát của bạn đã hoàn toàn sẵn sàng.
- Theo dõi Connection Pool tổng thể: Giám sát sát sao Database Connection Pool. Trong Monolith, một module chạy chậm có thể giữ kết nối database lâu và làm cạn kiệt pool của toàn ứng dụng.
- Áp dụng Module-Level Tagging: Đảm bảo mọi log và metric đều được đính kèm
module_idtĩnh để dễ dàng lọc, phân tích lỗi theo từng team phụ trách trên các hệ thống như ClickHouse, ELK hay Datadog.
Observability trong Monolith rõ ràng, rẻ tiền và hiệu quả. Nhưng nếu hệ thống của bạn đang là Microservices (hoặc một Spaghetti Monolith tồi tệ) và bạn muốn hợp nhất chúng lại thành Modular Monolith, bạn nên bắt đầu từ đâu? Phần 6: Migration Playbook sẽ cung cấp lộ trình chi tiết.
🔗 Đọc thêm các chuyên đề liên quan:
- Kiến trúc Microservices Golang & DDD
- Triển khai Agentic AI Swarm trong Production với OpenClaw & LiteLLM
- Kiến trúc Microservices Golang gRPC: Protobuf, TLS & Middleware
← Chương trước: Part 4: Đơn Giản Hóa CI/CD & Atomic Deployments | Mục lục Series | Chương tiếp theo: Part 6: Lộ Trình Chuyển Đổi (Migration Playbook) – Hợp Nhất →
