27 điểm bởi GN⁺ 2025-12-03 | 2 bình luận | Chia sẻ qua WhatsApp
  • Cấu trúc một writer duy nhất và đặc tính nhúng của SQLite được chứng minh qua thực nghiệm là yếu tố giúp tăng khả năng mở rộng và hiệu năng
  • Trong cùng điều kiện, Postgres giảm xuống 348 TPS khi có độ trễ mạng, trong khi SQLite đạt 44.096 TPS nhờ loại bỏ mạng
  • Tận dụng mô hình một writer duy nhất với xử lý theo lô và giao dịch phân nhỏ dựa trên SAVEPOINT giúp đạt tối đa 186.157 TPS, và 102.545 TPS trong cấu hình ổn định
  • Định luật Amdahl giải thích nút thắt cổ chai của cơ sở dữ liệu dựa trên mạng, còn SQLite duy trì hiệu quả cao nhờ tránh được điểm nghẽn này
  • Kết quả này nhấn mạnh khả năng ứng dụng SQLite trong môi trường cục bộtầm quan trọng của việc loại bỏ nút thắt mạng

Cấu trúc của SQLite và môi trường thử nghiệm

  • SQLite không có MVCC và chỉ cho phép một writer, nhưng chính cấu trúc này lại tạo điều kiện cho khả năng mở rộng cao
    • Là cơ sở dữ liệu nhúng nên không có overhead mạng
  • Benchmark được thực hiện trên MacBook Pro (2021) dùng Apple M1 Pro, RAM 16GB
  • Thử nghiệm không nhằm tối ưu hóa tuyệt đối mà để cho thấy vẫn có thể đạt thông lượng ghi cao trong các điều kiện thông thường

Định nghĩa TPS và ví dụ về giao dịch

  • TPS không chỉ là tốc độ ghi đơn thuần mà là giao dịch tương tác (Interactive Transaction)
    • Ví dụ: khi chuyển tiền giữa các tài khoản, nhiều truy vấn và mã ứng dụng được thực thi trong cùng một giao dịch
  • Giao dịch có thể rollback khi xảy ra lỗi nên đóng vai trò then chốt trong việc duy trì tính nhất quán

Cấu hình benchmark

  • Sử dụng virtual threads dựa trên Clojure để mô phỏng lượng lớn yêu cầu đồng thời
  • Postgres được cấu hình với connection pool dựa trên HikariCP, còn SQLite dùng một writer duy nhất và số kết nối đọc bằng số lõi CPU
  • Cả hai cơ sở dữ liệu đều dùng bảng account đơn giản với các trường id, balance và chèn 1 tỷ hàng
  • Hoạt động người dùng tuân theo phân phối power law (0.9995), với khoảng 100 nghìn người dùng hoạt động

Hiệu năng của cơ sở dữ liệu mạng (Postgres)

  • Trên cùng một máy chủ, Postgres đạt 13.756 TPS
  • Khi thêm độ trễ mạng 5ms, hiệu năng giảm mạnh xuống 1.214 TPS, và ở 10ms là 702 TPS
  • Sau khi áp dụng mức cô lập tuần tự hóa, con số giảm còn 660 TPS, và khi thêm truy vấn bổ sung thì xuống 348 TPS
  • Điều này cho thấy theo định luật Amdahl, nút thắt mạng giới hạn toàn bộ hiệu năng
    • Khi độ trễ mạng tăng, tranh chấp khóa giao dịch trở nên nghiêm trọng hơn, khiến hệ thống không thể mở rộng

Lợi thế nhúng của SQLite

  • Sau khi loại bỏ mạng, SQLite đạt 44.096 TPS
    • Khi nút thắt mạng biến mất, tác động của định luật Amdahl được giảm xuống mức tối thiểu
  • Khi áp dụng xử lý theo lô (batch processing) bằng cách tận dụng cấu trúc một writer duy nhất, hiệu năng tăng lên 186.157 TPS
    • Điều chỉnh kích thước lô động để tự động tối ưu độ trễ (latency) và thông lượng (throughput)

Giao dịch phân nhỏ bằng SAVEPOINT

  • Để tránh lỗi giao dịch riêng lẻ trong một lô, áp dụng giao dịch lồng nhau dùng SAVEPOINT
    • Khi lỗi xảy ra, chỉ rollback giao dịch đó, còn toàn bộ lô vẫn được giữ nguyên
  • Với cách này vẫn duy trì được 121.922 TPS

Kiểm thử tải hỗn hợp đọc/ghi

  • Cấu hình 75% tổng yêu cầu là đọc, 25% là ghi
  • Dùng thread pool đọc riêng để tách biệt, tránh yêu cầu đọc cản trở ghi
  • Kết quả đạt 102.545 TPS

Tóm tắt so sánh hiệu năng

Điều kiện Postgres SQLite
Không có mạng 13.756 44.096
Độ trễ 5ms 1.214 n/a
Độ trễ 10ms 702 n/a
10ms + tuần tự hóa 660 n/a
Xử lý theo lô n/a 186.157
Xử lý theo lô + SAVEPOINT n/a 121.922
Xử lý theo lô + SAVEPOINT + đọc n/a 102.545

Kết luận

  • SQLite đạt TPS cao hơn rất nhiều so với cơ sở dữ liệu dựa trên mạng nhờ mô hình một writer duy nhất và cấu trúc nhúng
  • Hiệu quả được tối đa hóa bằng cách tránh giới hạn nút thắt mạng mà định luật Amdahl chỉ ra
  • Toàn bộ mã nguồn đã được công khai trên GitHub, và các tài liệu về định luật Amdahl, power law, các trường hợp mở rộng SQLite cũng được cung cấp kèm theo
  • SQLite là một lựa chọn rất hiệu quả cho xử lý giao dịch hiệu năng cao trong môi trường cục bộ

2 bình luận

 
ppp123 2025-12-10

Nếu chỉ dùng trong môi trường cục bộ, không cần ra máy chủ bên ngoài, thì ý là không cần phải nộp thứ “thuế” mang tên mạng đúng không. (VFS vs Socket)

 
GN⁺ 2025-12-03
Ý kiến Hacker News
  • Tôi đang xây dựng một máy chủ ORM/CRUD protobuf lai dựa trên SQLite
    Mã nguồn và giải thích có tại GitHub - accretional/collector
    Có thể đạt downtime 5~15ms khi sao lưu thời gian thực, xếp hàng hàng trăm yêu cầu đọc/ghi, độ trễ CRUD tổng thể ở mức khoảng 1ms, và cả sao lưu streaming dựa trên WAL
    Trước đây tôi chỉ dùng Postgres và Spanner, nhưng nếu chỉ cần thêm tính năng phân vùng vào Collector thì có lẽ tôi sẽ không quay lại dùng Postgres nữa

    • Tôi cũng tò mò không biết bạn đã cân nhắc cách dùng filesystem có atomic snapshot như BTRFS để thực hiện sao lưu không downtime với SQLite + WAL chưa. Chỉ cần chụp snapshot, sao lưu từ từ rồi xóa đi là được
  • Điểm yếu là toàn bộ dữ liệu và xử lý đều phải nằm trên một máy duy nhất
    Nếu dùng instance AWS u-24tb1.112xlarge (448 vcore, 24TB RAM, 64TB EBS) thì vẫn còn khá dư dả

    • Nhưng nếu thuê máy chủ bare metal của Hetzner thì hiệu năng mỗi core cao hơn 2~3 lần, trong khi chi phí giảm 90%
    • Kích thước DB tối đa về mặt lý thuyết của SQLite được tài liệu chính thức nêu là 281TB. Trên thực tế giới hạn filesystem nhỏ hơn, nhưng nó vẫn hoạt động bình thường
    • Scale-up trên một máy là ổn định, nhưng thiếu tính đàn hồi (elasticity). Khi lưu lượng tăng đột biến thì либо phải cấp phát dư thừa, либо chấp nhận sự cố
    • Xem liên kết yourdatafitsinram.net hỏi rằng “dữ liệu của bạn có vừa trong RAM không?”, tôi nghĩ với node đơn hiệu năng cao thì máy chủ chuyên dụng tốt hơn EC2
  • Bài viết nhấn mạnh hiệu quả của SQLite, nhưng tôi cảm thấy tiêu chí so sánh chưa rõ ràng
    Vì ban đầu giả định kiến trúc máy chủ tách biệt, rồi lại đo hiệu năng của DB nhúng cục bộ
    Nếu cùng điều kiện, Postgres chạy local và được tinh chỉnh cũng có thể cho hiệu năng tương tự

    • SQLite nhanh hơn cả Postgres trên cùng một máy. Dùng cấu hình triển khai thực tế làm chuẩn để thử nghiệm là hợp lý hơn
    • Cũng có thể bọc SQLite phía sau bộ xử lý request để chạy trên máy chủ khác. Cuối cùng thì DB chỉ là tổ hợp giữa bộ xử lý request và nơi lưu trữ
    • Raw throughput trên một hộp đơn là điều quan trọng. SQLite nhanh hơn PG 10 lần, và PG càng có transaction phức tạp thì càng chậm
    • Nói rằng “vậy thì SQLite không phải đối tượng để so sánh” là quá đơn giản. Bài viết sẽ ngắn đi rất nhiều
    • SQLite không chỉ phù hợp cho mobile hay embedded mà còn hợp với ứng dụng máy chủ có mức đồng thời thấp. Nó không phải DB chỉ dành cho web server
  • Việc giới hạn Postgres ở 8 kết nối có thể là một nút thắt cổ chai
    Sẽ tốt hơn nếu công bố cả mức sử dụng CPU và thread, rồi thử lại với connection pool lớn hơn

    • Việc đặt connection pool theo số core (8) là chấp nhận được, nhưng nếu có sleep trong transaction thì sẽ thành nút thắt
      Nếu tăng lên 64 kết nối thì throughput có thể tăng gấp 8 lần. Cần mở rộng cấu hình client cho đến khi chạm giới hạn
    • Tôi thấy các con số trong bài này khó tin. Tôi còn đạt TPS cao hơn nhiều với cả MySQL chạy qua mạng
  • Điểm cốt lõi là nhận ra độ trễ mạng có phải nút thắt hay không
    Với nhiều workload, một DB local bình thường còn nhanh hơn một DB remote xuất sắc
    Điều quan trọng không phải là “DB nào tốt nhất” mà là “có cần vượt qua ranh giới mạng hay không

    • (Tác giả) Đúng vậy. Đây không phải tranh luận SQLite vs Postgres mà là để nói về giới hạn của DB qua mạng
    • Tất nhiên nếu để mọi thứ trong bộ nhớ và dùng Redis hay Memcache thì hiệu năng sẽ tăng rất dễ. Nhưng khi đó luật chơi đã khác
  • DB kiểu mạng có ưu điểm là dễ tái triển khai ứng dụng
    Có thể khởi chạy instance mới rồi tắt cái cũ, gần như đạt triển khai không gián đoạn
    Nếu đặt SQLite trên cùng instance thì khi thay thế phải dựng lại DB nên phức tạp hơn. Tôi muốn biết trong vận hành thực tế bạn có gặp vấn đề này không

    • Muốn dùng SQLite trong production thì cần storage bền vững và NVMe. Thường sẽ vận hành trên một máy chủ bare metal đơn
      Khi migration có thể sẽ có downtime. Nhờ Litestream mà bây giờ việc sao chép và sao lưu đã dễ hơn
    • SQLite hỗ trợ truy cập đa tiến trình, nên cũng có thể thay thế không gián đoạn bằng cách khởi chạy tiến trình mới rồi tắt tiến trình cũ
  • Tác giả đặt PRAGMA synchronous="normal", mà thiết lập này không thực hiện fsync mỗi lần
    Để so sánh công bằng thì nên đặt thành "full"

    • Nhưng trong chế độ WAL thì "normal" cũng ổn. Khi mất điện thì mất độ bền, nhưng tính nhất quán của transaction vẫn được giữ
  • Tôi tò mò cấu hình HA (khả dụng cao) của SQLite sẽ như thế nào
    Ít nhất cũng phải đạt mức có thể tự động failover

    • SQLite là một thư viện C, nên có thể mở rộng bằng các dự án như rqlite, litestream, litefs
      Hiện tôi đang phân vân giữa Postgres và SQLite (bao gồm litestream).
      Ứng dụng của tôi cho phép một ít downtime, nên scale dọc trên một máy đơn giản và rẻ hơn
    • Gần đây dự án multi-master tên Marmot đã hồi sinh sau 2 năm.
      Marmot GitHub mới được thêm cơ chế sao chép dựa trên gossip
  • Tôi muốn biết có trường hợp nào thực sự đẩy SQLite đến giới hạn trong production hay không

  • Tôi muốn hỏi ý kiến về giới hạn số người dùng của SQLite vs Postgres trong môi trường web app hoặc thương mại điện tử thông thường là khoảng bao nhiêu
    SQLite với các bản cập nhật gần đây cho phép đọc đồng thời nhưng vẫn chỉ cho phép một ghi duy nhất
    Tôi muốn biết khi nào điều này trở thành vấn đề, và nếu có tính đến mở rộng thì liệu bắt đầu với Postgres có tốt hơn không