Skip to content

Cloud Storage FUSE — POSIX Interface Trên Object Storage

Tại Sao Quan Trọng Trong Production

Cloud Storage FUSE (gcsfuse) là bridge giữa POSIX filesystem semantics và GCS object model — hai thế giới có cơ chế vận hành hoàn toàn khác nhau. Nhiều team dùng gcsfuse để cho applications "thấy" GCS như một local directory mà không cần sửa code. Nhưng semantic gaps giữa POSIX và object storage tạo ra những failure modes rất khó debug: silent data corruption, unexpected write behavior, và performance cliffs không rõ nguyên nhân.


Internal Model — Cách FUSE Hoạt Động

Kernel FUSE Interface

FUSE (Filesystem in Userspace) là Linux kernel mechanism cho phép implement filesystem trong user-space process. Kernel intercept filesystem syscalls (open, read, write, stat...) và forward sang FUSE daemon qua /dev/fuse.

Application process
    │ open("file.txt", O_RDONLY)

Linux VFS (Virtual Filesystem Switch)
    │ filesystem mounted? → FUSE

/dev/fuse character device
    │ FUSE protocol message

gcsfuse daemon (user space)
    │ GCS API call

GCS object storage

gcsfuse là FUSE daemon implement filesystem semantics trên GCS. Khi bạn mount:

bash
gcsfuse my-bucket /mnt/gcs

gcsfuse process chạy trong background, chặn tất cả VFS calls đến /mnt/gcs, translate sang GCS API calls.

Object Name → Directory Translation

GCS không có directory concept — chỉ có flat key-value store. gcsfuse simulate directories bằng cách interpret slash character trong object name:

GCS objects:
  "data/2024/jan/file1.csv"
  "data/2024/feb/file2.csv"
  "data/readme.txt"

gcsfuse hiển thị:
  /mnt/gcs/
  ├── data/
  │   ├── 2024/
  │   │   ├── jan/
  │   │   │   └── file1.csv
  │   │   └── feb/
  │   │       └── file2.csv
  └── readme.txt

Directory listing trong gcsfuse thực chất là ListObjects API call với prefix filter. Không có real directory objects trừ khi bucket có hierarchical namespace (HNS) enabled.

Write Path — Bất Đối Xứng Nghiêm Trọng

Write path của gcsfuse có đặc điểm quan trọng: writes phải buffer toàn bộ object vào local tmp trước khi upload:

write(fd, data, 1MB)
  → gcsfuse buffer vào /tmp/gcsfuse-XX (local disk)
  
write(fd, data, 1MB)  # lần 2
  → gcsfuse buffer tiếp vào /tmp/gcsfuse-XX

close(fd)  # hoặc flush
  → gcsfuse upload TOÀN BỘ object lên GCS
  → Object cũ bị replace hoàn toàn

Điều này có hệ quả:

  1. Cần local disk space bằng kích thước object đang write
  2. Write không visible cho GCS cho đến khi close/flush
  3. Với file lớn (checkpoint ML model, video), write latency = upload time toàn bộ file
  4. Nếu process crash trước close, write bị lost hoàn toàn

Tuy nhiên, kể từ gcsfuse version gần đây: files lớn hơn 2MB hỗ trợ append partial writes, nhưng vẫn cần buffer portion đó trước khi upload.

Read Path — Sequential vs Random Access

Sequential reads (đọc từ đầu đến cuối): gcsfuse stream data từ GCS, performant.

Random reads (seek đến offset cụ thể rồi đọc): gcsfuse cần GET request với Range header cho mỗi random access. Mỗi seek có thể tạo ra một HTTP request mới với overhead connection setup.

python
# Performant qua gcsfuse
with open("/mnt/gcs/large-file.parquet", "rb") as f:
    data = f.read()  # sequential, 1 HTTP GET

# Kém performant qua gcsfuse
with open("/mnt/gcs/large-file.parquet", "rb") as f:
    f.seek(100_000_000)  # HTTP GET Range: bytes=100000000-...
    chunk1 = f.read(1024)
    f.seek(50_000_000)   # HTTP GET Range: bytes=50000000-...
    chunk2 = f.read(1024)

Parquet readers, database engines, hay bất kỳ code nào dùng random access pattern sẽ có performance kém qua gcsfuse.


Caching Layers

gcsfuse có ba tầng caching để giảm API calls:

1. Stat Cache (Metadata Cache)

Cache kết quả của stat() syscall (file size, modification time, permissions). Giảm số lượng GetObject metadata requests.

bash
gcsfuse --stat-cache-ttl=60s --stat-cache-capacity=65536 my-bucket /mnt/gcs

TTL càng dài → fewer API calls nhưng stale metadata. Với versioned buckets hoặc buckets có nhiều writers, stale stat cache có thể dẫn đến reading wrong version.

2. List Cache (Directory Cache)

Cache kết quả của readdir() (directory listings). Mỗi ls lệnh trigger ListObjects API call — với nhiều ls calls, cache giảm đáng kể API costs.

bash
gcsfuse --dir-mode=755 --stat-cache-ttl=300s my-bucket /mnt/gcs

3. File Cache (Data Cache)

Kể từ gcsfuse v1.0+, hỗ trợ file data caching — cache actual object data trên local disk. Đặc biệt hữu ích cho AI/ML workloads với checkpoint reads.

bash
gcsfuse --cache-dir=/ssd-cache \
  --file-cache-max-size-gb=100 \
  my-bucket /mnt/gcs

File cache chứa full objects — lần đầu read tải về và cache, lần sau read từ local disk. Phù hợp cho read-heavy, repeated access patterns.


POSIX Semantic Gaps

gcsfuse không POSIX compliant — đây là điểm quan trọng nhất cần hiểu trước khi deploy.

GCS không hỗ trợ multiple references đến cùng object. ln (hard link) sẽ fail.

Không Có Atomic Directory Operations

rename trên directory trong POSIX là atomic. Trong gcsfuse (không có HNS):

rename("/mnt/gcs/dir-old", "/mnt/gcs/dir-new")
→ gcsfuse list tất cả objects với prefix "dir-old/"
→ Copy từng object sang "dir-new/" prefix
→ Delete từng object cũ

Không atomic — partial rename có thể xảy ra nếu crash giữa chừng. Với HNS enabled, rename directories là atomic.

Không Có File Locking

flock(), fcntl() locks không work qua gcsfuse. Applications rely vào file locking (database engines, some logging systems) sẽ không hoạt động đúng.

Concurrent Writers — Precondition Check

gcsfuse dùng generation precondition để detect concurrent writes:

Writer A: open("file.txt") → read generation=100
Writer B: open("file.txt") → write → generation=101
Writer A: write → close → upload với ifGenerationMatch=100
→ GCS trả 412: generation không match (hiện là 101)
→ gcsfuse return EEXIST hoặc EIO tùy context

Điều này ngăn silent overwrite nhưng cũng nghĩa là concurrent writes luôn fail. Chỉ một writer thành công, những cái còn lại nhận error.

Không Có Metadata Propagation

gcsfuse không upload object metadata chuẩn (như mtime) trừ khi được cấu hình đặc biệt. File modification time có thể không được preserved qua FUSE mount.


Performance Characteristics & Anti-Patterns

Latency So Với Local Filesystem

Mỗi file operation qua gcsfuse ít nhất là 1 HTTP round trip đến GCS. Với regional bucket cùng region, latency ~2-10ms/operation. So sánh với local SSD: ~0.1ms.

ls /mnt/gcs/large-dir/    # 1000 objects → có thể cần nhiều ListObjects calls
                          # Latency: 100ms - vài giây tùy số objects

ls /local-ssd/large-dir/  # Milliseconds

Directories với hàng triệu objects không nên list thường xuyên qua gcsfuse.

Throughput For AI/ML Workloads

gcsfuse được tối ưu cho AI/ML use case:

  • Parallel downloads: Tự động parallelize downloads cho cùng object (multi-threaded streaming)
  • Prefetching: Read-ahead caching cho sequential workloads
  • Rapid Bucket support: Kể từ gcsfuse 3.7.1, hỗ trợ Rapid Bucket với throughput cao hơn
bash
# Tối ưu gcsfuse cho training data
gcsfuse \
  --implicit-dirs \
  --file-cache-max-size-gb=200 \
  --cache-dir=/tmp/gcsfuse-cache \
  --max-conns-per-host=100 \
  training-data-bucket /mnt/training-data

Anti-Pattern: Database Files Trên gcsfuse

Đặt database files (SQLite, RocksDB, PostgreSQL data dir) trên gcsfuse mount là anti-pattern nghiêm trọng:

  • Databases cần random read/write access → performance cliff
  • File locking không work → corruption risk
  • WAL (write-ahead log) semantics không được đảm bảo
  • GCS không hỗ trợ in-place byte-range writes

Anti-Pattern: Object Versioning Với gcsfuse

Buckets với object versioning enabled tạo ra undefined behavior với gcsfuse. Mỗi write tạo noncurrent versions, nhưng gcsfuse không biết về versioning — có thể đọc wrong version hoặc create unexpected noncurrent objects.

Recommendation: Bucket dùng với gcsfuse không nên enable object versioning.

GKE Integration

Trong GKE, gcsfuse được tích hợp qua GKE FUSE sidecar (gke-gcsfuse-sidecar):

yaml
annotations:
  gke.io/fuse-annotation: "true"
volumes:
  - name: gcs-fuse-vol
    csi:
      driver: gcsfuse.csi.storage.gke.io
      volumeAttributes:
        bucketName: my-training-data
        mountOptions: "file-cache-max-size-gb=100"

Sidecar inject tự động, mount bucket trong Pod container. Workload Identity được dùng để authenticate, không cần key files.


Khi Nào Dùng gcsfuse

Phù hợp:

  • ML training jobs đọc large files (model weights, training datasets)
  • Batch processing pipelines đọc data từ GCS
  • Applications cần đọc config/model files từ GCS mà không muốn thay đổi code
  • Read-heavy workloads với repeated access (file cache tận dụng tốt)

Không phù hợp:

  • Databases hay stateful applications cần file locking
  • Workloads với nhiều small random reads/writes
  • Applications cần atomic directory operations
  • High-frequency write workloads (checkpoint mỗi giây)

References