10 điểm bởi GN⁺ 2024-01-16 | 1 bình luận | Chia sẻ qua WhatsApp

Bật/tắt chế độ Wal2

  • Chế độ "Wal2" của SQLite rất giống với chế độ "wal (Write-Ahead Logging)".
  • Để chuyển cơ sở dữ liệu sang chế độ wal2, dùng lệnh PRAGMA journal_mode = wal2;.
  • Không thể chuyển trực tiếp từ chế độ "wal" sang "wal2"; trước tiên phải chuyển sang chế độ rollback.
  • Để chuyển cơ sở dữ liệu từ chế độ wal sang wal2, dùng PRAGMA journal_mode = delete; rồi sau đó PRAGMA journal_mode = wal2;.
  • Cơ sở dữ liệu ở chế độ wal2 chỉ có thể được truy cập bằng các phiên bản SQLite được biên dịch từ nhánh đó.
  • Nếu cố dùng phiên bản SQLite khác, sẽ phát sinh lỗi SQLITE_NOTADB.
  • Để chuyển cơ sở dữ liệu wal2 sang chế độ rollback để mọi phiên bản SQLite đều có thể truy cập, dùng lệnh PRAGMA journal_mode = delete;.

Ưu điểm của chế độ Wal2

  • Trong chế độ wal hiện có, khi writer ghi dữ liệu vào cơ sở dữ liệu, tệp cơ sở dữ liệu không bị sửa trực tiếp mà dữ liệu mới được nối thêm vào tệp "-wal".
  • Các thao tác đọc sẽ đọc dữ liệu từ cả tệp cơ sở dữ liệu gốc và tệp "-wal".
  • Tại một thời điểm nào đó, dữ liệu sẽ được sao chép từ tệp "-wal" sang tệp cơ sở dữ liệu; việc này được gọi là "checkpoint".
  • Checkpoint có thể được thực hiện tường minh qua PRAGMA wal_checkpoint hoặc sqlite3_wal_checkpoint_v2(), hoặc tự động bằng cách cấu hình PRAGMA wal_autocheckpoint (thiết lập mặc định).
  • Checkpointer không chặn writer, và writer cũng không chặn checkpointer.
  • Tuy nhiên, nếu writer ghi vào cơ sở dữ liệu trong lúc checkpoint đang diễn ra, dữ liệu mới sẽ tiếp tục được nối vào cuối tệp wal, khiến tệp wal có thể tiếp tục phình to.
  • Ở chế độ wal2, không còn vấn đề tệp wal tăng kích thước vô hạn ngay cả khi checkpointer không có cơ hội hoàn tất mà không bị gián đoạn.
  • Chế độ wal2 dùng hai tệp wal thay vì một ("-wal" và "-wal2").
  • Khi dữ liệu được ghi, writer bắt đầu nối dữ liệu mới vào tệp wal thứ nhất.
  • Khi tệp wal thứ nhất đủ lớn, writer sẽ bắt đầu nối dữ liệu vào tệp wal thứ hai.
  • Sau đó, tệp wal thứ nhất có thể được checkpoint; khi tệp wal thứ hai đủ lớn và tệp thứ nhất đã được checkpoint, hệ thống sẽ chuyển lại sang tệp thứ nhất.

Lập trình ứng dụng

  • Từ góc nhìn người dùng, khác biệt chính giữa chế độ wal và wal2 liên quan đến checkpoint.
  • Ở chế độ wal, có thể thử checkpoint bất cứ lúc nào; nhưng ở chế độ wal2, chỉ có thể checkpoint sau khi writer đã chuyển sang tệp wal "còn lại".
  • Ở chế độ wal, sau khi transaction được commit, wal-hook (callback) được gọi với đối số là tổng số trang của tệp wal.
  • Ở chế độ wal2, wal-hook được gọi với đối số là tổng số trang chưa được checkpoint trong cả hai tệp wal, hoặc với đối số 0 nếu tệp wal "còn lại" đang trống hoặc đã được checkpoint.
  • Khuyến nghị client sử dụng cùng chiến lược checkpoint cho cơ sở dữ liệu wal2 như với chế độ wal.
  • Wal-hook được gọi sau khi transaction được commit xuống đĩa và khóa cơ sở dữ liệu được giải phóng, nhưng vẫn xảy ra bên trong lời gọi sqlite3_step().
  • Trong hệ thống BEGIN CONCURRENT, thay vì chạy checkpoint bên trong wal-hook, có thể dùng một luồng trì hoãn công việc này cho đến sau khi application mutex được giải phóng.

Ý kiến của GN⁺

  • Chế độ wal2 của SQLite cung cấp một phương thức journaling mới giúp cải thiện tính đồng thời và hiệu quả của cơ sở dữ liệu.
  • Việc giải quyết vấn đề tệp wal tăng không giới hạn là điều quan trọng để cải thiện độ ổn định và hiệu năng của hệ thống.
  • Với việc đưa vào wal2, các nhà phát triển cần xem xét lại chiến lược checkpoint của cơ sở dữ liệu và triển khai logic checkpoint phù hợp để đạt được khả năng đồng thời tốt hơn.

1 bình luận

 
GN⁺ 2024-01-16
Ý kiến trên Hacker News
  • Ở chế độ WAL2, hai tệp WAL được sử dụng thay vì một. Các tệp được đặt tên là "<cơ sở dữ liệu>-wal" và "<cơ sở dữ liệu>-wal2". Khi dữ liệu được ghi vào cơ sở dữ liệu, thao tác ghi bắt đầu bằng việc thêm dữ liệu mới vào tệp WAL thứ nhất. Khi tệp WAL thứ nhất đủ lớn, thao tác ghi sẽ chuyển sang thêm dữ liệu vào tệp WAL thứ hai. Tại thời điểm này, tệp WAL thứ nhất có thể được checkpoint (và sau đó có thể bị ghi đè), và khi tệp WAL thứ hai đủ lớn và tệp thứ nhất đã được checkpoint, hệ thống lại chuyển về tệp WAL thứ nhất. Quá trình này tiếp tục lặp lại.

    • Cách này rất hợp lý, đến mức tôi không hiểu vì sao ngay từ đầu chế độ WAL lại không được triển khai theo cách này. Có lẽ từng bị xem là một tối ưu hóa quá sớm.
    • Hy vọng chế độ này sẽ sớm được cung cấp rộng rãi.
  • Bedrock

    • Bedrock là một nhánh còn thú vị hơn.
    • Bao gồm các tính năng WAL2 + CONCURRENT.
    • Đây là nhánh mà Expensify dùng để mở rộng tới 4M QPS trên một node duy nhất (từ 6 năm trước).
  • Có cung cấp liên kết tới left-right primitive, một kỹ thuật tương tự chế độ WAL2.

    • Kỹ thuật này có từ trước bản triển khai được liên kết nhưng được tái khám phá một cách độc lập, và được viết ra đặc biệt để hỗ trợ một cơ sở dữ liệu SQL hiệu năng cao khác là Noria.
  • Ở chế độ WAL2, hai tệp WAL được sử dụng thay vì một. Các tệp được đặt tên là "<cơ sở dữ liệu>-wal" và "<cơ sở dữ liệu>-wal2".

    • Tò mò không biết sẽ có bao nhiêu người xóa tệp wal, vì họ có thể nghĩ rằng sau khi chuyển sang wal2 thì tệp wal là phần còn thừa.
  • Microsoft SQL Server dùng một kiến trúc tương tự, nhưng thay vì các tệp log riêng biệt, nó cấp phát các Virtual Log Files (VLF) bên trong tệp log vật lý (trên đĩa). Các VLF được cấp phát trong một ring buffer và có thể lên tới hàng nghìn.

  • Có thể thấy tính năng này vẫn chưa được phát hành.

  • Tôi luôn băn khoăn rằng WAL tồn tại để giúp duy trì tính toàn vẹn dữ liệu và phục hồi sau sự cố. Tuy nhiên, bản thân tệp này được ghi theo lô (được commit xuống đĩa một cách đáng tin cậy) chứ không phải sau mọi thay đổi của cơ sở dữ liệu, nhằm đạt hiệu năng. Điều này chẳng phải làm suy yếu mục đích đó sao? Nói chung, không chỉ riêng cơ sở dữ liệu này, tôi vẫn chưa tìm được câu trả lời cho vấn đề đó.

  • Tò mò không biết điều này sẽ ảnh hưởng thế nào tới các hệ thống SQLite phân tán mới như Litestream.

  • Vậy về cơ bản đây là double buffering cho cơ sở dữ liệu? Nghe hợp lý đấy.

  • Chế độ WAL2 đã được đưa vào benchmark của nghiên cứu backend HC-tree.