- PostgreSQL 18 có thể nhân bản cơ sở dữ liệu gần như tức thì bằng cách kết hợp chiến lược sao chép tệp (FILE_COPY) với tính năng clone của hệ thống tệp
- Khi dùng thiết lập mới
file_copy_method = clone, có thể tận dụng tính năng clone của các hệ thống tệp hiện đại (FICLONE) như XFS, ZFS, APFS
- Theo kết quả benchmark, khi nhân bản cơ sở dữ liệu 6GB, phương thức WAL_LOG hiện có mất khoảng 67 giây, còn phương thức clone được rút xuống mức khoảng 0,2 giây
- Cơ sở dữ liệu được nhân bản ban đầu sẽ chia sẻ cùng các khối vật lý, nhưng khi có thao tác ghi sẽ được tách ra bằng copy-on-write
- Tuy nhiên, chỉ có thể nhân bản khi không có kết nối đang hoạt động, và có ràng buộc là chỉ hoạt động trong một hệ thống tệp duy nhất
Cấu trúc nhân bản dựa trên template của PostgreSQL
- Trong PostgreSQL, khi chạy lệnh
CREATE DATABASE dbname, hệ thống nội bộ sẽ nhân bản cơ sở dữ liệu template1 để tạo cơ sở dữ liệu mới
- Điều này tương đương với
CREATE DATABASE dbname TEMPLATE template1
- Có thể chỉ định một cơ sở dữ liệu khác thay cho
template1, nên cũng có thể nhân bản bằng template do người dùng tự định nghĩa
- Trong PostgreSQL 18, hệ thống template này được mở rộng thành cấu trúc có thể nhân bản tức thì
CREATE DATABASE ... STRATEGY
- Từ PostgreSQL 15, tham số
CREATE DATABASE ... STRATEGY đã được giới thiệu, cho phép chọn phương thức nhân bản
- Giá trị mặc định là
WAL_LOG, thực hiện nhân bản theo đơn vị khối thông qua Write-Ahead Log
- Cách này giảm tải I/O và cải thiện hỗ trợ đồng thời, nhưng chậm khi nhân bản dữ liệu lớn
- Nếu chỉ định
STRATEGY=FILE_COPY, có thể quay lại cách sao chép tệp truyền thống, và trong PostgreSQL 18, dựa trên đó đã có thêm tùy chọn nhân bản mới
FILE_COPY và file_copy_method
- Thiết lập
file_copy_method trong PostgreSQL 18 điều khiển cách sao chép tệp ở cấp hệ điều hành
- Mặc định là
copy, đọc toàn bộ byte và ghi sang vị trí mới
- Nếu đổi sang
clone, hệ thống sẽ dùng tính năng clone của hệ thống tệp (FICLONE) để nhân bản tức thì mà không tốn thêm dung lượng ngay lập tức
- Hệ thống tệp được hỗ trợ: XFS, ZFS, APFS, FreeBSD ZFS
- Quy trình cấu hình
- Triển khai PostgreSQL cluster trên hệ thống tệp tương ứng
- Thiết lập
file_copy_method = clone rồi reload
Kết quả benchmark
- Sau khi tạo cơ sở dữ liệu thử nghiệm khoảng 6GB (
source_db), tiến hành so sánh hai phương thức
- Phương thức
WAL_LOG: 67.000ms (khoảng 67 giây)
- Phương thức
FILE_COPY + clone: 212ms
- Với cùng kích thước dữ liệu, xác nhận tăng tốc hơn khoảng 300 lần
- Cơ sở dữ liệu được nhân bản (
fast_clone) gần như không sử dụng thêm dung lượng đĩa
Nguyên lý hoạt động của dữ liệu được nhân bản
- Khi dùng
file_copy_method = clone, chỉ metadata của hệ thống tệp được sao chép, nên hai cơ sở dữ liệu chia sẻ cùng các khối vật lý
- Kích thước cơ sở dữ liệu mà PostgreSQL báo cáo vẫn là kích thước logic giống nhau (khoảng 6GB)
- Khi phát sinh thao tác ghi, copy-on-write (COW) sẽ hoạt động và tách các trang liên quan
- Trang chứa các hàng đã sửa đổi
- Trang nơi tuple mới được ghi
- Các trang chỉ mục, FSM, visibility map và các trang tương tự
- Ngay cả khi chạy
VACUUM, cũng sẽ phát sinh thêm việc tách trang
Xác minh khối chia sẻ trên XFS
- Dùng lệnh
filefrag -v để kiểm tra xem hai cơ sở dữ liệu có chia sẻ cùng khối vật lý hay không
- Ở trạng thái ban đầu, tất cả extents đều được hiển thị là
shared
- Khi cập nhật một số hàng, 40 khối đầu tiên (khoảng 160KB) sẽ bị tách và chuyển sang địa chỉ vật lý khác nhau
- Các extents còn lại vẫn tiếp tục ở trạng thái chia sẻ
Lưu ý và ràng buộc
- Cơ sở dữ liệu nguồn không được có kết nối đang hoạt động tại thời điểm nhân bản
- Đây là ràng buộc của PostgreSQL, không phải vấn đề của hệ thống tệp
- Trong môi trường production, thông thường sẽ dùng một cơ sở dữ liệu template riêng biệt
- Chỉ có thể nhân bản trong cùng một hệ thống tệp
- Nếu nhiều tablespace nằm trên các mount point khác nhau, hệ thống sẽ quay về sao chép thông thường
- Trên dịch vụ cloud managed (AWS RDS, Google Cloud SQL, v.v.), không thể dùng tính năng này vì không có quyền truy cập hệ thống tệp
- Trong môi trường VM tự quản hoặc bare metal, có thể kiểm soát hoàn toàn
Kết luận
- Tính năng
file_copy_method = clone của PostgreSQL 18 tận dụng trực tiếp khả năng clone ở cấp hệ điều hành để
rút ngắn mạnh thời gian nhân bản cơ sở dữ liệu dung lượng lớn
- Có thể triển khai workflow cơ sở dữ liệu có thể nhân bản tức thì và reset dễ dàng trong các môi trường test, phát triển và học tập
- Tuy nhiên, cần thiết kế vận hành có cân nhắc đến ràng buộc kết nối đang hoạt động và tính đơn nhất của hệ thống tệp
1 bình luận
Ý kiến Hacker News
Với những ai không thể chờ hoặc cần khả năng cô lập instance hoàn toàn của PG18, tôi đã tạo ra Velo, một công cụ phân nhánh tức thì dùng ZFS snapshot
Nó hoạt động với mọi phiên bản PostgreSQL, và mỗi nhánh có container cùng cổng riêng biệt
Với DB 100GB, có thể tạo trong khoảng 2~5 giây
Khác với cách của PG18 ở chỗ nó không chia sẻ một instance duy nhất mà cung cấp khả năng cô lập máy chủ hoàn toàn
Liên kết GitHub
Trước đây khi công ty chuyển sang RDS, chúng tôi đã tự xây một hệ thống tương tự
Vì trong quá trình migration production thường xuyên xảy ra sự cố, nên để ngăn điều đó, chúng tôi đã tự động hóa các bước sau
Nhờ quy trình này, chúng tôi bắt được nhiều bug chỉ xuất hiện riêng ở production mà local hay CI không phát hiện ra
Sau đó chúng tôi tự động hóa bằng một script Ruby đơn giản, và tôi nghe nói đến giờ họ vẫn còn dùng script đó
Đây là lần đầu tôi biết chiến lược template cloning có thể cấu hình được
Tôi đã dùng Neon để tạo môi trường tích hợp thời gian thực, và trong dự án Golang pgtestdb của mình, mỗi test sẽ tạo một DB Postgres riêng với toàn bộ schema migration đã được áp dụng
Trước đây tôi từng thấy ở một startup họ dùng btrfs để tạo DB staging tức thì, nên thật thú vị khi thấy ý tưởng tương tự cứ lặp lại
Kiểu nhân bản và kiểm thử nhanh này là một ưu điểm lớn của Postgres và Sqlite, và tôi ước Clickhouse hay MySQL cũng làm được như vậy
Dạo này PostgreSQL có vẻ đã trở thành DB vạn năng bao phủ gần như mọi nhu cầu SQL
Lại còn miễn phí
Giờ tôi tự hỏi liệu còn lý do gì để dùng một SQL DB khác nữa không
Clickhouse nhanh hơn rất nhiều cho analytics, và những DB như Cassandra lại có lợi thế với workload thiên về ghi
Nói cách khác, mỗi DB vẫn có điểm mạnh riêng
Khi dữ liệu tăng lớn, sẽ xuất hiện suy giảm hiệu năng hoặc vấn đề migration
Trường hợp của tôi là performance của partitioning mặc định quá kém nên tôi phải tự triển khai partition tùy chỉnh
Lựa chọn này gây ra nhiều tác động tiêu cực khi tải tăng cao
Bài viết blog của Uber cũng từng đề cập đến chủ đề này
Dù vậy, trong môi trường cloud thì tôi vẫn tin tưởng Postgres nhất
Vì thế trong các triển khai OLTP quy mô lớn, MySQL vẫn thường được dùng nhiều hơn (ví dụ: YouTube, Uber)
Dùng cấu trúc dữ liệu bất biến (HAMT) thì có thể tạo DB clone tức thì bất kể loại filesystem nào
Tôi nói là lý thuyết, nhưng thực ra đã từng tự triển khai rồi
Tôi không hiểu vì sao lại không có nhiều DB dựa trên HAMT hơn
Liên kết tài liệu liên quan
Tôi không biết rằng trong Postgres v15, WAL_LOG đã trở thành mặc định
Trong môi trường CI test song song, quay lại chiến lược FILE_COPY có vẻ hợp lý hơn
Tôi đã mở issue liên quan trong dự án cũ integresql
Tôi từng tạo một công cụ GUI đơn giản pgtt để test ứng dụng dựa trên Postgres ở local
Nó giúp đơn giản hóa việc thiết lập môi trường dev rất nhiều
Có vẻ điều này sẽ hữu ích cho công việc lặp đi lặp lại với SQL migration
Tôi cũng đọc các bài viết khác trên blog này và nhìn chung thấy rất xuất sắc
Đặc biệt là lần đầu tôi biết tới range type của Postgres
Tôi tự hỏi liệu MariaDB có tính năng như vậy không
Tôi đang đau đầu vì việc đưa DB về trạng thái ban đầu sau mỗi test quá chậm
Vì production đang dùng MariaDB nên rất khó đổi DB
Dù vậy, phía Postgres trông vẫn hấp dẫn hơn
Cách này khá hiệu quả
AWS cũng hỗ trợ tính năng tương tự
Tài liệu Aurora clone
Điều này không thực tế cho integration test