Câu chuyện của một developer về những cực đoan trong cơ sở dữ liệu đã khơi mào cuộc tranh luận sôi nổi về cách tiếp cận đúng đắn cho việc lưu trữ dữ liệu và logic nghiệp vụ. Câu chuyện kể lại hành trình của một team từ cơn ác mộng stored procedure đến một giải pháp key-value store cũng có vấn đề không kém, làm nổi bật cách các quyết định kiến trúc có thể lắc lư từ cực này sang cực khác mà không tìm được điểm cân bằng.
Vấn Đề Ban Đầu: Stored Procedures Mất Kiểm Soát
Hệ thống legacy gặp phải trường hợp điển hình của việc over-engineering cơ sở dữ liệu. Logic nghiệp vụ hoàn toàn nằm trong các stored procedure có những join phức tạp trải rộng trên nhiều cơ sở dữ liệu SQL Server . Những procedure này trở thành nút thắt cổ chai về hiệu suất, chiếm dụng thời gian CPU trên các database server có hạn và tạo ra các vấn đề độ trễ không thể dự đoán khi query plan thay đổi bất ngờ. Hệ thống cũng phụ thuộc rất nhiều vào MSDTC ( Microsoft Distributed Transaction Coordinator ), thường xuyên gây ra deadlock và sự cố hệ thống.
MSDTC: Một dịch vụ của Microsoft điều phối các transaction trên nhiều cơ sở dữ liệu hoặc hệ thống, nhưng nổi tiếng về việc gây ra deadlock và các vấn đề về độ tin cậy.
Các vấn đề của hệ thống ban đầu:
- Logic nghiệp vụ được nhúng trong các stored procedure phức tạp
- Nhiều cơ sở dữ liệu SQL Server trên các máy chủ khác nhau
- Phụ thuộc nặng vào MSDTC gây ra tình trạng deadlock
- Các thay đổi kế hoạch truy vấn không thể dự đoán gây ra timeout
- Thời gian build từ 15-30 phút đòi hỏi môi trường phát triển VM
Phản Ứng Thái Quá: Chủ Nghĩa Cực Đoan Key-Value Store
Để đáp ứng với những rắc rối SQL , team kiến trúc đã có một bước ngoặt mạnh mẽ theo hướng ngược lại. Họ quyết định từ bỏ hoàn toàn cơ sở dữ liệu quan hệ, lựa chọn các key-value store nguyên thủy chỉ cung cấp bốn thao tác cơ bản: đọc, chèn, cập nhật và xóa các key đơn lẻ. Không có transaction, không có batching, không cho phép các truy vấn phức tạp.
Cách tiếp cận này tạo ra những vấn đề mới gần như ngay lập tức. Dữ liệu nghiệp vụ có tính quan hệ cao phải được làm phẳng thành các tài liệu JSON lớn, đôi khi lên đến hàng trăm kilobyte. Vì key-value store thiếu các tính năng của document database, ngay cả những cập nhật nhỏ cũng yêu cầu đọc toàn bộ tài liệu, thực hiện thay đổi trong application code, rồi ghi lại tất cả. Team cuối cùng đã thêm nén để giảm overhead mạng, nhưng điều này khiến dữ liệu không thể kiểm tra được bằng các công cụ cơ sở dữ liệu tiêu chuẩn.
Hạn chế của Key-Value Store:
- Chỉ có 4 thao tác: Đọc, Chèn, Cập nhật, Xóa các khóa đơn lẻ
- Không hỗ trợ giao dịch hoặc xử lý theo lô
- Các tài liệu JSON có thể lên đến hàng trăm kilobyte
- Yêu cầu đọc/ghi toàn bộ tài liệu cho việc cập nhật từng phần
- Cần nén Gzip, làm hỏng các công cụ tiêu chuẩn
Sự Bùng Nổ Độ Phức Tạp: Hệ Thống Checkpointing
Không có database transaction, team đã xây dựng một hệ thống checkpointing phức tạp để xử lý tính nhất quán dữ liệu. Mọi thao tác ghi đều yêu cầu tạo một UUID và lưu trữ nó như một checkpoint, sau đó nhúng UUID này vào tài liệu đích để ngăn chặn các thao tác trùng lặp trong quá trình retry. Cách tiếp cận này gần như tăng gấp đôi số lượng database round trip so với hệ thống ban đầu, khiến các vấn đề độ trễ trở nên tệ hơn thay vì tốt hơn.
Trong thực tế, các thao tác ghi vào cùng một cơ sở dữ liệu trước đây yêu cầu 5-10 round trip, giờ đây yêu cầu gần gấp đôi số lượng trip cho các thao tác checkpointing bổ sung.
Chi phí hệ thống Checkpointing:
- Tạo UUID cho mọi thao tác ghi
- Lưu trữ checkpoint trong hệ thống riêng biệt
- Nhúng UUID vào các tài liệu đích
- Gần như tăng gấp đôi số lượt truy cập cơ sở dữ liệu (từ 5-10 lên ~20)
- Logic thử lại phức tạp để đảm bảo tính idempotency
Quan Điểm Cộng Đồng: Cuộc Tranh Luận Về Con Đường Trung Dung
Cộng đồng phát triển vẫn còn chia rẽ sâu sắc về các lựa chọn kiến trúc cơ sở dữ liệu. Nhiều developer chia sẻ những câu chuyện kinh hoàng về stored procedure trở thành những con quái vật không thể bảo trì, với logic nghiệp vụ rải rác trên các hệ thống cơ sở dữ liệu và ngôn ngữ khác nhau. Những người khác lại cho rằng stored procedure vẫn có chỗ đứng, đặc biệt cho các thao tác dữ liệu hàng loạt và khi nhiều ứng dụng cần truy cập cùng một cơ sở dữ liệu với các quy tắc nghiệp vụ nhất quán.
Cuộc tranh luận ORM versus raw SQL cũng nổi lên mạnh mẽ trong các thảo luận. Một số developer xem ORM như những công cụ tăng năng suất giúp tiết kiệm thời gian dù có chi phí hiệu suất, trong khi những người khác coi chúng như những abstraction che giấu các cơ hội tối ưu hóa cơ sở dữ liệu quan trọng. Sự đồng thuận dường như là việc tuân thủ một cách mù quáng bất kỳ cách tiếp cận đơn lẻ nào thường dẫn đến vấn đề.
ORM: Các công cụ Object-Relational Mapping dịch giữa các bảng cơ sở dữ liệu và các object ngôn ngữ lập trình, làm cho các thao tác cơ sở dữ liệu dễ dàng hơn nhưng đôi khi kém hiệu quả hơn.
Bài Học Về Sự Cân Bằng Kiến Trúc
Câu chuyện này minh họa một pattern phổ biến trong phát triển phần mềm: giải quyết một vấn đề cực đoan bằng cách lắc sang cực đoan ngược lại. Cách tiếp cận stored procedure ban đầu có những vấn đề chính đáng, nhưng giải pháp key-value đã vứt bỏ hàng thập kỷ tối ưu hóa cơ sở dữ liệu cùng với các vấn đề. Một cách tiếp cận cân đối hơn có thể bao gồm việc refactor các stored procedure, cải thiện chiến lược indexing, hoặc áp dụng một ORM hiện đại với việc giám sát hiệu suất cẩn thận.
Câu chuyện này phục vụ như một lời nhắc nhở rằng các quyết định kiến trúc nên dựa trên các yêu cầu kỹ thuật cụ thể thay vì phản ứng với những điểm đau trong quá khứ. Đôi khi giải pháp tốt nhất không nằm ở sự thay đổi mang tính cách mạng, mà ở những cải tiến tiến hóa cho các hệ thống hiện có.
Tham khảo: Wrong ways to use the databases, when the pendulum swung too far