WiredTiger MVCC (P4/4): So với PostgreSQL và lỗi thường gặp
Ở phần trước: một snapshot giữ mở trong lúc 300.000 lệnh $inc vẫn đọc tổng n là 0, còn đọc mới nhất là 300.000. Version cũ không được dọn khi snapshot còn mở, và file history store không co lại ngay.
- Cần đọc trước: Ba lab về snapshot bị giữ
- Dẫn tới: Concurrency: Locks, Latches & Tickets. Với bài này, WiredTiger MVCC khép lại tại đây.
So với PostgreSQL
Cùng một bài toán: nhiều transaction cùng đọc và ghi một dòng/document. [tài liệu] PostgreSQL cũng dùng MVCC: mỗi câu lệnh thấy một snapshot, và đọc không chặn ghi, ghi không chặn đọc. Khác biệt nằm ở chỗ cất version cũ:
| PostgreSQL | MongoDB (WiredTiger) | |
|---|---|---|
| Version cũ nằm ở đâu | ngay trong heap (file của bảng): UPDATE ghi một dòng mới, dòng cũ vẫn ở đó cho tới khi bị xoá | version mới nhất trong file của bảng; version cũ trong update chain (cache) rồi sang một file riêng, history store |
| Ai biết dòng nào thấy được | mỗi dòng mang xmin và xmax (transaction id tạo ra và làm nó hết hiệu lực) trong header | mỗi update mang transaction id và timestamp; snapshot gồm danh sách transaction đang chạy cộng read timestamp |
| Ai xoá version cũ | VACUUM (autovacuum chạy nền); không có nó dòng chết tích tụ thành bloat | reconciliation và checkpoint, khi oldest timestamp tiến lên; không có tiến trình riêng tên "vacuum" |
| Một transaction chạy lâu làm gì | VACUUM không xoá được dòng chết còn có thể bị nhìn thấy; khi cứu sự cố transaction ID wraparound, manual khuyên kết thúc transaction mở lâu | pinned timestamp bị giữ, history store giữ nhiều version hơn; bị chặn bởi transactionLifetimeLimitSeconds |
[tài liệu] Manual PostgreSQL: UPDATE hoặc DELETE không xoá ngay version cũ của dòng, vì MVCC cần nó; VACUUM thông thường xoá dòng chết và đánh dấu chỗ trống để dùng lại nhưng không trả không gian cho hệ điều hành (trừ các page cuối bảng trống hẳn); VACUUM FULL viết lại cả bảng. [quan sát] History store của WiredTiger trong lab cũng dùng lại chỗ trống chứ không co ngay (30,44 MB trống, file 32,89 MB). Nghe giống nhau nhưng không tương đương: ở PostgreSQL, dòng chết nằm trong chính bảng (làm bảng phình) và VACUUM chạy riêng; ở WiredTiger version cũ nằm ở file riêng. Bài này không đo PostgreSQL, nên không kết luận bên nào bloat nhiều hơn hay nhanh hơn.
Những lỗi thường gặp
- "MVCC nghĩa là không có lock và không có xung đột." Đọc không chặn ghi, nhưng hai lệnh ghi vào cùng một document vẫn xung đột, kể cả khi sửa hai field khác nhau (
WriteConflictở trường hợp 1 của lab ở phần trước (Update chain và history store)). Lock và ticket nằm ở bài Concurrency. - Quên commit hoặc abort transaction. Transaction còn mở giữ pinned timestamp ở lại phía sau:
stable − pinnedở Lab 1 của phần trước (Ba lab về snapshot bị giữ) là 480 giây chỉ vì một transaction không ai đóng. Tìm chúng bằng$currentOpvớiidleSessions: true. - Tin history store là miễn phí. 300.000 update trên 100 document sinh 31 đến 33 MB history store khi giữ snapshot, 27 MB khi không giữ gì nhưng để cửa sổ mặc định, và 2,1 GB ở lab 200 KB: thêm lượng ghi cho reconciliation và thêm đĩa.
- Nhầm oplog với nơi lưu các version cũ. Oplog để secondary phát lại, nằm trong collection có giới hạn kích thước, và không cho bạn đọc document ở thời điểm cũ. Version cũ sống trong update chain và history store, không có API công khai.
- Cho rằng giữ snapshot lâu luôn làm app chậm. Ở quy mô lab, độ trễ và cache không khác giữa hold và control. Cái giá đo được là lượng ghi vào history store và dung lượng đĩa; đọc chậm thêm chỉ thấy khi 100.000 update dồn lên một hot document (Lab 2). Cache thật sự chật là chuyện của bài Cache, Eviction & Working Set.
- Mong file
WiredTigerHS.wtnhỏ lại ngay khi snapshot đóng. Phần trống dùng lại được sau vài phút, file co lại muộn hơn nhiều: đọc cảfile bytes available for reuse.
Cột mốc: Bạn đã có thể so cách MVCC của WiredTiger và PostgreSQL cất version cũ, nói vì sao transaction quên commit giữ timestamp lại, và tìm chúng bằng
$currentOp. Bài này khép lại tại đây.
Hỏi & đáp
Cùng bài toán nhiều transaction đọc và ghi một dòng/document, khác biệt chính giữa PostgreSQL và WiredTiger mà bài nêu là gì?
Ứng dụng quên commit hoặc abort một transaction snapshot, và stable − pinned ở lab giữ snapshot của phần trước là 480 giây chỉ vì thế. Cách tìm thủ phạm, và vì sao nó gây hậu quả đó?
Nếu bỏ hết thuật ngữ: một thư viện luôn in ấn bản mới thay vì tẩy chữ trên bản cũ, và đóng dấu thời điểm in lên từng bản. Ai bước vào nhận bản mới nhất lúc đó và đọc bản đó đến hết, dù thư viện in thêm bao nhiêu. Chồng bản gần nhất để trên bàn, bản cũ hơn xuống tầng hầm. Thư viện chỉ vứt một ấn bản khi chắc chắn không ai còn cầm bản đó hoặc bản cũ hơn. Có một người ngồi lì cả tuần với ấn bản cũ thì cả chồng bản từ lúc đó phải ở lại, và nếu thư viện còn quy ước giữ mọi bản của năm phút gần nhất thì chồng đó đã dày sẵn kể cả khi chẳng ai ngồi lì. Hai người cùng sửa một cuốn thì người sửa sau bị từ chối và phải làm lại, dù hai người sửa hai trang khác nhau.
Bài tiếp theo
Bài này nói ai thấy gì và ai xung đột với ai ở tầng version. Nó chưa nói những gì chặn nhau thật sự: hai thread cùng chạm một page, hai lệnh cùng xin một lock, nhiều lệnh xếp hàng chờ được chạy.
Concurrency: Locks, Latches & Tickets trả lời: lock của MongoDB ở các tầng, latch của WiredTiger bên trong, ticket là gì và vì sao nó giới hạn số thao tác chạy đồng thời, và phân biệt rõ logical isolation, physical locking và concurrency control.
Tài liệu tham khảo
- MongoDB: WiredTiger Storage Engine (Snapshot History Retention,
WiredTigerHS.wt, checkpoints) - MongoDB: Server Parameters (
minSnapshotHistoryWindowInSeconds,transactionLifetimeLimitSeconds) - MongoDB: Read Isolation, Consistency, and Recency
- MongoDB: Read Concern "snapshot" (
atClusterTime,SnapshotTooOld) - MongoDB: Transactions: Production Considerations (lifetime, WiredTiger cache)
- MongoDB:
serverStatus(wiredTigersection) - WiredTiger: Transactions
- WiredTiger: Timestamps
- WiredTiger: History Store
- WiredTiger: Snapshots
- WiredTiger: Cache
- WiredTiger: Eviction
- WiredTiger: B-Trees (update chains)
- PostgreSQL: Concurrency Control, Introduction (MVCC)
- PostgreSQL: Routine Vacuuming
- PostgreSQL: Database Page Layout (
t_xmin,t_xmax)