Kiến Trúc Distributed MinIO

Trong phần 1, chúng ta đã tìm hiểu cách triển khai MinIO Distributed Cluster với nhiều node và nhiều ổ đĩa. Trong phần 2, chúng ta sẽ đi sâu hơn vào kiến trúc lưu trữ của MinIO, bao gồm:

  • Cơ chế Erasure Coding (EC)

  • Replication trong MinIO

  • Overhead và hiệu suất lưu trữ

  • Số lượng disk/node có thể hỏng tối đa

Tổng quan nhanh trước khi vào chi tiết

Ở mức cao: MinIO trong chế độ Distributed dùng Erasure Coding (Reed–Solomon) để chia object thành nhiều data shard + parity shard, xếp các shard này vào một erasure set (một tập ổ/drives). Thông số chính bạn cần hiểu:

  • S = kích thước erasure set (số ổ trong set)

  • M = số parity shards (parity)

  • K = số data shards = S − M
    MinIO cho phép đặt parity giữa 0S/2 (và khuyến nghị cấu hình mặc định tương đương S/2 để độ bền cao). MinIOMinIO Blog

1) Erasure Coding — cơ chế & ý nghĩa (kỹ thuật)

Reed–Solomon & tham số (k, m)
  • Khi client PUT một object, MinIO chia object thành K data shards, rồi sinh M parity shards bằng thuật toán Reed–Solomon. Tổng cộng S = K + M shards.

  • M (parity) cho biết số ổ có thể mất (về nguyên tắc) mà object vẫn có thể phục hồi (read) — vì bạn cần ít nhất K shards để reconstruct.

MinIO mặc định / gợi ý
  • MinIO (trước đây) mặc định dùng tỉ lệ K = S/2, M = S/2 (tức parity = 50%), nhưng giờ có thể cấu hình parity bất kỳ trong khoảng 0..S/2. Cấu hình parity = S/2 là cấu hình độ bền cao mà MinIO khuyến nghị.

Ví dụ số (để dễ hình dung)
  • Nếu 1 erasure set có S = 16 drives và bạn để parity M = 8 (mặc định N/2):

    • K = 8 (data shards), M = 8 (parity).

    • Mất tối đa 8 ổ và bạn vẫn có thể đọc (vì còn K=8 shards). Nhưng để vừa đọc vừa ghi an toàn (xem phần Quorum), số ổ mất được chấp nhận cho read+write sẽ khác (thường thấp hơn 1).

2) Erasure set — khái niệm rất quan trọng

  • Erasure set là tập các ổ (drives) mà MinIO dùng để lưu shards cho một stripe (một object). MinIO tự động nhóm drives thành các erasure setstripe một object vào đúng 1 erasure set (không phân mảnh object ra khắp toàn bộ cluster). Vì vậy một object chỉ phụ thuộc vào drives trong set đó.

Hệ quả kiến trúc:

  • Nếu toàn bộ drives của một set bị mất — những object từng nằm trên set đó sẽ bị mất (mặc dù nhiều drives ở set khác vẫn khoẻ). Vì vậy kích thước set và cách phân bố drives qua node / rack quyết định “blast radius”.

Về kích thước set: MinIO thường tạo set có kích thước trong khoảng 4 → 16 drives (tùy triển khai); bạn thiết kế tổng số drives phải chia đều thành các set hợp lý.

3) Read quorum & Write quorum — công thức và ý nghĩa

MinIO có quorum đọcquorum ghi (số shards / drives tối thiểu cần online để đọc/ghi an toàn cho một object). Múi quan trọng:

  • K (read quorum) = số data shards cần thiết để phục hồi object (về bản chất K = S − M). Nếu bạn có ít hơn K shards, MinIO không thể reconstruct object từ parity.

  • Write quorum thường bằng K, nhưng có 1 ngoại lệ: khi parity = S/2 (tức M = S/2, code-rate = 1/2) MinIO áp thêm +1 (write quorum = K+1) để tránh split-brain (kịch bản: nửa set và nửa set bị chia mạng, mỗi nửa ghi khác nhau). Vì vậy khi M = S/2, write quorum = K + 1.

Ứng dụng công thức (ví dụ)
  • S = 16, M = 8 ⇒ K = 8.

    • Read: cần ≥8 shards → có thể chấp nhận đến 8 ổ hỏng (read-only).

    • Write: với M = S/2, write quorum = K + 1 = 9 → vì vậy để vừa đọc & ghi bình thường bạn chỉ chịu được tối đa 7 ổ hỏng (16 − 9 = 7).

Tóm tắt: read-only tolerance ≥ write+read tolerance; khi bạn thiết kế HA cần chú ý con số cho write quorum vì nó quyết định dịch vụ có thể tiếp tục chấp nhận ghi hay không.

4) Bao nhiêu ổ / node có thể hỏng an toàn? (cách tính nhanh)

Công thức cơ bản cho read-only khả năng chịu lỗi = M (parity).
Công thức cho đọc + ghi (để dịch vụ vẫn có thể ghi) ≈ S − (write_quorum) where write_quorum = K (thường) hoặc K+1 (nếu M=S/2).

Ví dụ phổ biến:

  • Set S=4, M=2 (K=2) → read: có thể mất 2 ổ (vẫn đọc), write: nếu M=S/2 => write quorum = 3 → chịu tối đa 1 ổ để vẫn ghi.

  • Set S=8, M=4 (K=4) → read: mất 4 ổ vẫn read; write: write quorum=5 → chịu tối đa 3 ổ để vẫn write.

Lưu ý: đây là tính trên một erasure set. Tổng khả năng chịu lỗi toàn cluster phụ thuộc cách sets được phân bố (nhiều set = phân tán rủi ro) và rủi ro đồng thời (node/rack-level failure).

5) Hiệu năng: trade-offs (EC vs Replication)

  • EC (Erasure Coding): tiết kiệm dung lượng (ví dụ parity = 50% → usable = 50% raw), nhưng ghi đắt hơn do:

    • CPU để tính parity (encode) và decode khi reconstruct.

    • Ghi nhiều đường mạng (shards phải truyền qua mạng tới nhiều drives/nodes).

    • Với object nhỏ overhead cao hơn (metadata + nhiều PUT nhỏ).

  • Replication (multiple full copies): ghi nhanh hơn (kết thúc khi đủ replica ack), nhưng tốn dung lượng (ví dụ 2-way replication = 50% usable cũng giống EC:50% theo mặt dung lượng, nhưng cách tiêu tốn khác; 3-way replication tốn nhiều hơn).
    MinIO khuyến nghị EC cho 1 datacenter vì tối ưu dung lượng/chi phí; dùng replication (bucket replication) cho multi-site/DR.

6) Healing / phục hồi sau lỗi (thao tác & nội dung)

Khi drive/node thất bại

Quy trình điển hình:

  1. Unmount / thay drive hỏng.

  2. Gắn drive mới, mount vào cùng mountpoint.

  3. MinIO tự phát hiện drive mới, bắt đầu healing để rebuild shards trên drive đó — quá trình này chỉ tác động chủ yếu đến drive thay thế và có tác động hiệu năng giới hạn.

Khi MinIO heal một object?
  • MinIO có healing on GET/HEAD: khi client đọc object và nếu thiếu shards, MinIO sẽ reconstruct (dùng shards còn lại + parity) để phục vụ request và có thể sửa (heal) shards bị thiếu. Ngoài ra có object scanner chạy nền để kiểm tra & heal một số object theo lịch. Bạn có thể chủ động chạy mc admin heal để trigger heal.

Cẩn trọng vận hành: không can thiệp trực tiếp tới dữ liệu trên drives (di chuyển, xóa file), MinIO yêu cầu exclusive access; nếu thao tác thủ công có thể gây hỏng dữ liệu.

7) Thiết kế set / phân bố để giảm “blast radius”

Một vài nguyên tắc thực tế:

  • Đừng gom quá nhiều drives quan trọng vào cùng 1 rack. Nếu một set nằm hoàn toàn trong 1 rack và rack mất, những object trong set đó mất. Phân bố drives trong set qua nhiều node/rack sẽ tăng khả năng chịu lỗi server/rack.

  • Chia thành nhiều set nhỏ hơn (ví dụ nhiều set S=4 thay vì 1 set S=16) → mỗi object chỉ trải trên ít drives, nghĩa là khi một set mất, chỉ 1 phần dữ liệu bị ảnh hưởng (nhược điểm: tổng overhead parity trên toàn cluster có thể tăng). Quyết định này cần trade-off giữa độ bền, phạm vi mất dữ liệuhiệu năng.

  • Không trộn drive sizes / types (tốc độ khác nhau gây bottleneck), đồng bộ firmware/driver để tránh tính không đều.

8) Tính toán dung lượng & ví dụ nhanh (công thức)

  • Raw capacity = sum(all drive capacities)

  • Usable capacity (với một set có K data, S total) = Raw × (K / S) = Raw × (1 − M/S)

    • Ví dụ S=16, M=8 → usable = Raw × (8/16) = Raw × 0.5 (50%).

Kế hoạch dư thừa: nếu muốn usable = X TB với parity mặc định S/2, bạn phải chuẩn bị Raw = 2 × X TB.

9) Một số lệnh vận hành hữu ích (quick ops)

  • Kiểm tra cluster:

mc admin info <alias>
  • Kiểm tra trạng thái object/shards: (xem shards missing)

mc admin object info <alias>/<bucket>/<object>
  • Trigger heal chủ động (cẩn thận, chạy trong maintenance window):

mc admin heal <alias> --recursive
  • Monitor logs & heal progress để xem IO/throughput:

mc admin service logs <alias>
mc admin top

Tác giả: Mạnh Hoàng

Tôi là Hoàng Mạnh, người sáng lập blog SysadminSkills.com. Tôi viết về quản trị hệ thống, bảo mật máy chủ, DevOps và cách ứng dụng AI để tự động hóa công việc IT. Blog này là nơi tôi chia sẻ những gì đã học được từ thực tế – đơn giản, ngắn gọn và áp dụng được ngay.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *