Tổng kết module — Lưu trữ & Filesystem
Cheat sheet ổ đĩa, filesystem, page cache và fsync; glossary, pitfall tổng hợp và self-assessment đối chiếu năm learning outcome của module.
TL;DR: Module này bóc bảy khái niệm nối nhau thành một chuỗi: cơ chế vật lý quyết định độ trễ, kiểu truy cập quyết định bạn trả khoản đó mấy lần, filesystem quyết định tên file tìm ra dữ liệu bằng cách nào, page cache quyết định lần đọc nào chạm đĩa, fsync quyết định lúc nào dữ liệu thật sự bền, và tầng lưu trữ quyết định giả định nào của bạn còn đứng vững. Đây là một trang để đánh dấu và quay lại.
Đã đi qua những gì
Bạn bắt đầu từ ba khối vật liệu khác nhau — đĩa từ quay, NAND flash, và cái nhãn NVMe hoá ra chỉ là giao thức — rồi thấy mọi con số hiệu năng đều là hệ quả suy ra được từ đó chứ không phải ma thuật của nhà sản xuất. Từ đó bạn leo dần lên: kiểu truy cập, lớp ánh xạ của filesystem, tầng đệm của kernel, ranh giới độ bền, và cuối cùng là chuyện gì xảy ra khi cả cái ổ đĩa nằm ở đầu bên kia một sợi cáp mạng. Bài lab khép lại bằng cách bắt bạn tự đo — vì một con số bạn tự tay lấy được đáng giá hơn mười bảng thông số đọc trên mạng.

🗺️ Cheat sheet
| Khái niệm | Cốt lõi | Pitfall hay gặp |
|---|---|---|
| Seek + chờ quay | 7200 vòng/phút cho ra ~4,17 ms chờ quay trung bình | Tưởng tăng tốc độ quay là giải được bài toán IOPS |
| Erase block | Ghi theo page, xoá theo khối 1–8 MiB | Tưởng ổ còn trống là còn block đã xoá sẵn |
| Wear leveling | Firmware rải lần ghi khắp ổ | Ghi đè nhiều lần để xoá dữ liệu nhạy cảm |
| NVMe vs AHCI | 65.535 hàng đợi so với 1 hàng 32 lệnh | Coi SSD và NVMe là hai loại để chọn một |
| Ba chỉ số | throughput ≈ IOPS × kích thước khối | Dùng IOPS cao để suy ra độ trễ thấp |
| dentry vs inode | Tên nằm ở thư mục, metadata nằm ở inode | Tưởng tên file nằm trong chính file |
| Hardlink | Dentry thứ hai trỏ cùng inode | Tưởng nó là bản sao tốn gấp đôi dung lượng |
| Page cache | Lần đọc thứ hai lấy từ RAM | Benchmark không xoá cache — đang đo RAM |
| Ngưỡng dirty | dirty_ratio 20% chặn tiến trình ghi | Không hiểu vì sao ghi khựng từng cơn |
fsync vs fdatasync | Cái sau bỏ metadata không cần cho đọc lại | Gọi fsync sau mỗi bản ghi, tụt throughput cả bậc |
| fsync thư mục | rename chỉ bền khi fsync cả thư mục cha | Mất cả hai file khi cúp điện |
| Block / file / object | Khác nhau ở chỗ ai giữ filesystem | Bê pattern rename nguyên tử lên object storage |
📖 Glossary module
| Thuật ngữ | Định nghĩa một câu |
|---|---|
| Seek | Thời gian đầu đọc HDD trượt sang track chứa dữ liệu cần đọc. |
| Rotational latency | Thời gian chờ mặt đĩa quay tới đúng sector sau khi đã tới đúng track. |
| Erase block | Đơn vị xoá nhỏ nhất của NAND, lớn hơn đơn vị ghi hàng trăm lần. |
| FTL | Tầng firmware ánh xạ địa chỉ hệ điều hành thấy sang vị trí vật lý thật trên NAND. |
| Write amplification | Tỉ số giữa lượng dữ liệu thật sự ghi xuống NAND và lượng ứng dụng yêu cầu ghi. |
| Wear leveling | Cơ chế rải các lần ghi đều khắp ổ để không ô nhớ nào mòn sớm. |
| Over-provisioning | Phần dung lượng nhà sản xuất giấu đi để firmware có chỗ xoay xở khi dọn dẹp. |
| IOPS | Số thao tác vào ra mỗi giây, khác với throughput và khác với độ trễ. |
| dentry | Mục trong thư mục ánh xạ một tên file sang số inode. |
| inode | Cấu trúc giữ metadata của file cùng bản đồ trỏ tới các khối dữ liệu. |
| Extent | Cách mô tả vùng dữ liệu bằng cặp "bắt đầu và độ dài" thay cho danh sách con trỏ block. |
| Page cache | Vùng RAM kernel dùng để giữ nội dung file đã đọc hoặc vừa ghi. |
| Dirty page | Trang trong page cache đã bị sửa nhưng chưa được ghi xuống thiết bị. |
| Write-back | Tiến trình nền của kernel đẩy trang bẩn xuống thiết bị theo lịch riêng. |
| Read-ahead | Kernel đoán trước phần sẽ đọc tiếp và nạp sẵn vào page cache. |
O_DIRECT | Cờ mở file bỏ qua page cache, hợp lý khi ứng dụng tự quản cache của mình. |
REQ_PREFLUSH / REQ_FUA | Hai yêu cầu ở tầng block buộc thiết bị xả bộ đệm hoặc ghi thẳng xuống vật liệu bền. |
| PLP | Tụ chống mất điện trong ổ doanh nghiệp, khiến bộ đệm của nó không còn volatile. |
| Close-to-open | Ngữ nghĩa của NFS: bên ghi đóng file, bên đọc mở lại thì mới chắc chắn thấy bản mới. |
| Object storage | Kho khoá-giá trị không có filesystem, không rename nguyên tử, không ghi đè một phần. |
⚠️ Pitfall tổng hợp
❌ Benchmark ổ đĩa mà không xoá page cache → ✅ Xoá cache trước mỗi lượt đo, hoặc dùng --direct=1 với fio. Không làm vậy thì bạn đang đo RAM, sai tới vài bậc độ lớn.
❌ Tin write() trả về là dữ liệu đã bền → ✅ Nó mới chỉ vào page cache; mặc định trang bẩn được phép nằm lại tới 30 giây. Muốn bền thì fsync, và phải kiểm tra giá trị trả về.
❌ fsync file mà quên fsync thư mục sau rename → ✅ Mở thư mục cha rồi fsync chính nó. Thiếu bước này, mất điện có thể xoá sạch cả file cũ lẫn file mới.
❌ Gọi fsync sau mỗi bản ghi cho chắc → ✅ Chi phí nhân theo số lần chờ, không theo số byte. Gom nhiều thay đổi rồi đồng bộ một lần, đúng cách database làm với write-ahead log.
❌ Dùng %util để kết luận NVMe bão hoà → ✅ Với thiết bị nhiều hàng đợi song song, chỉ số đó mất ý nghĩa. Xem độ trễ mỗi thao tác và độ sâu hàng đợi thực tế.
❌ Bê pattern ghi tạm rồi rename lên object storage → ✅ Ở đó không có rename nguyên tử. Ghi khoá mới có phiên bản rồi cập nhật một con trỏ duy nhất.
❌ Mount một volume block cho nhiều máy đọc-ghi → ✅ Filesystem giả định nó là chủ sở hữu duy nhất; hai bên cùng ghi là hỏng dữ liệu. Muốn dùng chung thì lên tầng file.
✅ Self-assessment
Bạn đã đạt module này nếu trả lời được:
- So sánh được HDD, SSD và NVMe về cơ chế vật lý và hệ quả lên độ trễ, IOPS, tuổi thọ — nếu chưa: đọc lại bài 01 mục 2 và 3.
- Dự đoán được chênh lệch giữa truy cập tuần tự và ngẫu nhiên từ cơ chế thiết bị, và đọc đúng ba chỉ số IOPS, throughput, latency — nếu chưa: bài 02.
- Giải thích được filesystem ánh xạ tên file sang khối dữ liệu qua inode, dentry và block allocation — nếu chưa: bài 03.
- Lần theo được đường một lần
write()từ page cache xuống mặt đĩa và quyết định khi nào bắt buộc gọifsync— nếu chưa: bài 04 và bài 05. - Chọn được giữa block, file và object storage dựa trên độ trễ và ngữ nghĩa nhất quán của workload — nếu chưa: bài 06.
Chưa chắc mục nào thì cách kiểm tra thật nhất là mở lại bài lab và đo. Số liệu tự tay lấy được sẽ nói cho bạn biết mình hiểu tới đâu.
🚀 Tiếp theo
Module sau đổi câu hỏi. Ở đây bạn hỏi dữ liệu nằm ở đâu; module Đường đi I/O & GPU hỏi dữ liệu đi đường nào để tới được biến trong chương trình. Bạn sẽ lần theo một lệnh read() xuyên hết các tầng — syscall, VFS, page cache, block layer, driver, rồi tới thiết bị và ngắt báo xong — và gặp lại chính page cache của module này ở đúng vị trí của nó trên tuyến đường.
Module đó cũng trả một lời hứa treo từ course đầu tiên của track: bài von Neumann từng nói "chi tiết trong bài sau về I/O", và bài sau đó chính là bài mở màn module 02.
📚 Tài liệu mở rộng
- SPDK — NAND Flash SSD Internals — cấp thấp về erase-before-write, FTL và over-provisioning.
- fsync(2) — man7.org — nguồn chính chủ cho khác biệt
fsyncvớifdatasync, và yêu cầu fsync thư mục. - Linux kernel — sysctl/vm — bốn ngưỡng điều khiển write-back của page cache.
- Linux kernel — writeback cache control —
REQ_PREFLUSHvàREQ_FUAở tầng block. - fio documentation — mọi tuỳ chọn cần cho việc đo lại nghiêm túc hơn bài lab.
Bài tiếp theo: Tổng quan module — Đường đi I/O & GPU
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên