Ba hệ tệp, cùng một máy, cùng một ảnh loop 2 GB, cùng một bộ phép đo. Bài này cũng là bài tôi mắc lỗi đo rõ nhất trong cả loạt.

So sánh ext4, xfs và btrfs

Sai lầm trước, kết quả sau

Lần đo đầu tiên tôi chạy một lần mỗi hệ tệp cho phép ghi tuần tự:

ext4    3.908 MB/s
xfs     1.231 MB/s
btrfs   2.535 MB/s

Kết luận rõ ràng: ext4 nhanh gấp 3,2 lần xfs. Một con số đẹp, dễ nhớ, dễ viết thành tiêu đề.

Chạy lại ba lần mỗi bên:

Lần 1 Lần 2 Lần 3
ext4 3.683 5.120 5.885 MB/s
xfs 4.923 4.063 5.689 MB/s
btrfs 3.012 3.631 3.606 MB/s

Hai dải trùm hoàn toàn lên nhau. Kết luận "3,2 lần" là nhiễu, không phải kết quả.

Con số 1.231 MB/s của xfs ở lần đầu thấp hơn cả ba lần đo sau, và tôi không biết vì sao — có thể là lần chạy đầu tiên trên hệ tệp vừa tạo, có thể là máy chủ bên dưới đang bận. Điều duy nhất chắc chắn là một lần đo không phải một phép đo.

Chuyện tương tự xảy ra với phép đo siêu dữ liệu: lần đầu ext4 cho 53.388 tệp/giây, các lần sau đều trên 138.000. Con số đầu là lúc bộ đệm còn lạnh.

Kết quả sau khi lặp lại

Phép đo ext4 xfs btrfs
Ghi tuần tự (MB/s) 3.683 / 5.120 / 5.885 4.923 / 4.063 / 5.689 3.012 / 3.631 / 3.606
Đọc ngẫu nhiên (IOPS) 32.165 35.861 32.858
Tạo tệp (tệp/giây) 138k / 154k / 151k 165k / 175k / 175k 180k / 184k / 184k
Ghi ngẫu nhiên + fsync (IOPS) 14.210 / 15.641 / 14.638 14.538 / 10.950 / 11.241 9.025 / 7.414 / 8.407

Thứ hạng đổi theo từng phép đo:

  • Ghi tuần tự: ext4 và xfs không phân biệt được; btrfs thấp hơn khoảng 30%.
  • Đọc ngẫu nhiên: cả ba như nhau. Không có gì để chọn.
  • Tạo tệp: btrfs ≥ xfs > ext4, chênh khoảng 1,25 lần.
  • Ghi ngẫu nhiên có fsync: ext4 nhanh nhất và ổn định nhất; btrfs chậm hơn khoảng 1,7 lần.

Không hệ tệp nào thắng ở cả bốn. Câu hỏi "hệ tệp nào nhanh hơn" không có câu trả lời; phải hỏi "nhanh hơn ở việc gì".

Vì sao btrfs chậm ở ghi ngẫu nhiên

btrfs là hệ tệp sao chép khi ghi: sửa 4 KB giữa một tệp không ghi đè tại chỗ mà ghi ra chỗ mới rồi cập nhật cây tham chiếu trỏ tới đó. Với fsync, cả chuỗi cập nhật cây phải xuống đĩa.

Đó là cái giá đổi lấy ảnh chụp tức thời, tổng kiểm tra dữ liệu, và khả năng quay lui — những thứ ext4 không có.

Với cơ sở dữ liệu, cái giá đó thường không đáng, và có cách giảm:

chattr +C /var/lib/postgresql/data     # tat sao chep khi ghi cho thu muc nay
mount -o nodatacow,noatime /dev/... /data

chattr +C phải đặt trên thư mục rỗng — tệp đã có dữ liệu không đổi được thuộc tính này.

Vì sao ext4 ổn định hơn ở fsync

Nhìn lại ba lần đo của xfs: 14.538, 10.950, 11.241. Lần đầu ngang ext4, hai lần sau thấp hơn 25%. ext4 thì 14.210, 15.641, 14.638 — dao động 10%.

Với một dịch vụ mà fsync nằm trên đường đi của mỗi giao dịch, độ ổn định quan trọng hơn giá trị trung bình. Một hệ thống nhanh hơn 5% nhưng thỉnh thoảng chậm đi 25% cho trải nghiệm xấu hơn.

Đây là lý do thực dụng khiến ext4 vẫn là mặc định cho nhiều triển khai cơ sở dữ liệu, dù xfs thắng ở nhiều bảng so sánh.

Chọn theo tính chất, không theo con số

Hệ tệp Mạnh ở Nên chọn khi
ext4 ổn định, ít bất ngờ, công cụ sửa lỗi trưởng thành mặc định; cơ sở dữ liệu; khi không muốn nghĩ nhiều
xfs tệp rất lớn, siêu dữ liệu song song, mở rộng online máy chủ tệp, kho dữ liệu, phân vùng lớn
btrfs ảnh chụp, tổng kiểm tra, nén, RAID mềm máy trạm, máy chủ sao lưu, nơi cần quay lui

Khoảng cách hiệu năng giữa chúng — trừ trường hợp fsync của btrfs — nhỏ hơn nhiều so với khoảng cách giữa việc cấu hình đúng và cấu hình mặc định. Một tuỳ chọn gắn kết duy nhất cho nhiều hơn cả việc đổi hệ tệp:

mount -o noatime,nodiratime /dev/sdb1 /data

noatime bỏ việc cập nhật thời gian truy cập — nghĩa là mỗi lần đọc không còn kéo theo một lần ghi siêu dữ liệu. Với tải đọc nhiều, đây là thay đổi lớn hơn mọi thứ trong bảng trên. (Nhân hiện đại mặc định relatime nên chỉ ghi khi mốc cũ hơn một ngày, đã đỡ nhiều — nhưng noatime vẫn hơn.)

Giới hạn của phép đo này

Ba hệ tệp nằm trên ảnh loop 2 GB trong một máy ảo, không phải trên phân vùng thật của ổ NVMe. Con số tuyệt đối không mang đi được.

Thứ mang đi được là hình dạng: đọc thì cả ba như nhau, tạo tệp thì btrfs và xfs hơn, fsync thì btrfs kém rõ rệt. Ba kết luận đó khớp với kiến trúc của chúng và sẽ lặp lại trên phần cứng thật.

Và mang đi được, quan trọng hơn cả: lặp lại phép đo ba lần trước khi tin bất cứ tỷ lệ nào.

Thử ba mươi giây

So hai hệ tệp trên chính máy bạn, có lặp lại:

for d in /mnt/a /mnt/b; do          # doi thanh hai duong dan that cua ban
  echo "=== $d ($(df -T $d | tail -1 | awk '{print $2}')) ==="
  for i in 1 2 3; do
    rm -rf $d/many; mkdir -p $d/many; sync
    t0=$(date +%s%N)
    i2=0; while [ $i2 -lt 10000 ]; do : > $d/many/f$i2; i2=$((i2+1)); done
    sync; t1=$(date +%s%N)
    echo "  lan $i: $(( 10000000000 / (t1-t0) )) tep/giay"
    rm -rf $d/many
  done
done

Nếu ba lần của cùng một hệ tệp chênh nhau hơn mức chênh giữa hai hệ tệp, bạn chưa đo được gì cả — và đó là tình huống phổ biến hơn nhiều so với người ta tưởng.

Phần sau: theo dõi I/O trong thực tế — iostat, iotop và cách đọc chúng cho đúng.