mateusz@systems ~/book/distributed-filesystems $ cat section.md

Distributed and Network Filesystems

Network filesystems allow multiple machines to share access to data, enabling collaboration and resource pooling. Understanding their trade-offs is critical: choosing the wrong filesystem for your workload can mean the difference between millisecond latencies and minute-long hangs, between graceful degradation and catastrophic data loss. This section introduces a framework for evaluating network filesystems across three key dimensions: semantics (what guarantees does the FS provide?), architecture (how does it scale and perform?), and failure modes (what breaks and how?). By understanding these dimensions, you'll know what to pay attention to when working with any network filesystem—even ones not covered here.

# Architecture Overview

Before diving into comparisons, let's visualize how these systems are structured. Architecture fundamentally determines scalability, failure modes, and performance characteristics.

NFS - Single Server Architecture

Client 1 Client 2 Client 3 NFS Server metadata + data single point of failure Local FS + Storage ext4 · XFS · ZFS
Single-server NFS — every operation funnels through one host: simple, but a hard throughput ceiling and a single point of failure.

Performance: All operations funnel through a single server, limiting throughput to one machine's capabilities. Metadata operations (stat, readdir) and data I/O compete for the same resources, creating contention under mixed workloads.

Resiliency: Server failure makes the entire filesystem unavailable—no failover, no redundancy. Common in simple deployments where simplicity outweighs HA requirements.

Lustre - Separated Metadata and Data

Client 1 Client 2 Client 3 metadata data MDS (metadata) OST 1 OST 2 OST 3 (data) (data) (data) ldiskfs or ZFS ldiskfs or ZFS ldiskfs or ZFS
Lustre — metadata and data are split: clients query the MDS (a single point of failure unless run HA) for namespace operations while striping data in parallel across multiple OSTs, each backed by its own ldiskfs or ZFS filesystem, for high aggregate throughput.

Performance: Separating metadata and data enables massive parallel throughput—clients can hit multiple OSTs simultaneously for striped files, achieving aggregate bandwidth that scales with OST count. Metadata server (MDS) handles namespace operations independently.

Resiliency: MDS remains a single point of failure (unless using HA config), but OST failures only affect files stored on that target. Ideal for HPC workloads with large sequential I/O patterns.

GPFS - Shared Disk with Distributed Locking

Client 1 Client 2 Client 3 Token-based locking NSD Server 1 NSD Server 2 NSD Server 3 Shared Storage SAN · NVMe-oF
GPFS — any node can act as both client and NSD server (all nodes shown can be either). Token-based locking gives cache coherency without constant round-trips to a central authority; NSD servers manage direct I/O to shared storage, so no single node is a point of failure.

Performance: Token-based locking enables cache coherency without constant server round-trips—nodes can cache data as long as they hold the appropriate token. Direct storage access eliminates data forwarding overhead.

Resiliency: No single point of failure—any NSD server can fail and others take over. Token manager is distributed across the cluster. Shared storage itself needs redundancy (RAID, replication). Trade-off: lock contention can hurt metadata-intensive workloads.

WekaFS - Distributed with Coherent Cache

Client 1 Client 2 Client 3 + Cache + Cache + Cache Cache coherency protocol Backend Backend Backend Node 1 Node 2 Node 3
WekaFS — every client keeps a local, coherent cache kept in sync by a distributed cache-coherency protocol. Clients fan out to distributed backend nodes over NVMe drives, so there is no single point of failure.

Performance: Every cached-mode client can use its host's Linux page cache in RAM, minimizing backend reads for hot data. Cache coherency protocol ensures consistency without sacrificing speed—reads hit local cache, writes invalidate remote copies. Distributed backend provides parallel access paths.

Resiliency: Fully distributed architecture with no single point of failure. Data is protected by WEKA's configurable distributed RAID (for example N+2, N+3, or N+4), and failures trigger automatic rebuild. Optimized for modern cloud-native and AI/ML workloads requiring both high throughput and low latency.

VAST - Disaggregated Shared Everything (DASE)

Client 1 Client 2 Client 3 NFS (optional multipath/RDMA) CNode 1 CNode 2 CNode 3 (CNode) (CNode) (CNode) NVMe-oF fabric (any CNode to any DBox) DBox 1 DBox 2 DBox 3 SCM + QLC SCM + QLC SCM + QLC
VAST's Disaggregated Shared Everything (DASE) architecture: NFS clients reach stateless CNodes running the protocol servers, optionally using the VAST NFS client for cross-CNode multipath and/or NFS over RDMA. Every CNode reaches every DBox over a shared NVMe-oF fabric — not just its own. DBoxes pair Storage Class Memory with QLC flash in an all-flash, erasure-coded tier.

Performance: VAST's "Disaggregated Shared Everything" (DASE) architecture separates stateless compute nodes (CNodes) from storage enclosures (DBoxes). Any CNode can access any DBox over NVMe-oF fabric, enabling global data reduction and eliminating isolated data islands. Supports standard NFS access plus optional nconnect, VAST-client multipath, and NFS over RDMA—simpler than parallel FS clients but with competitive throughput.

Resiliency: No single point of failure—CNodes are stateless and can fail without data loss. DBoxes use Storage Class Memory (SCM) for metadata durability and QLC flash for capacity. Data is erasure-coded across DBoxes. Trade-off: relies on NFS semantics (close-to-open by default), and the SCM write buffer in the DBoxes can become a bottleneck under sustained high-throughput writes.

# Filesystem Semantics Comparison

POSIX defines a set of filesystem behaviors that applications rely on—atomic operations, consistency guarantees, and locking primitives. Network filesystems make different trade-offs between full POSIX compliance and performance. Understanding these semantics tells you what your application can safely assume.

Filesystem POSIX Compliance Consistency Model Locking Support
NFS Close [1] Close-to-open [2]
Relaxed during open
NLM (advisory) [3]
Lockd daemon
Lustre Full POSIX Strict coherency [4]
Byte-range via locks
LDLM [5]
Distributed locks
GPFS Full POSIX Token-coherent caching
Conflicting access coordinated by token revoke/downgrade
Token-based [6]
Byte-range locks
WekaFS Full POSIX Strong consistency [7]
Coherent distributed cache
POSIX locks
Distributed mgmt
VAST NFS-based [8] Close-to-open default
Strong consistency option
NFS locks (NLM/v4)
Advisory locking

[1] NFSv3 supports reliable exclusive creation through CREATE(EXCLUSIVE); NFSv4 integrates open and lock state into the core protocol.
[2] NFS close-to-open: changes by one client visible to others only after close()+open(); see deep-dive section for details on edge cases
[3] NLM (Network Lock Manager) provides advisory locks; server crash can lose lock state
[4] Lustre LDLM (Distributed Lock Manager) provides strong cache coherency via lock callbacks
[5] Lustre locks can be revoked under contention, forcing clients to flush dirty data
[6] GPFS tokens grant read/write/lock permissions; distributed algorithm ensures consistency
[7] WekaFS maintains cache coherency across all clients via distributed consensus protocol
[8] VAST uses enhanced NFS (multipath, RDMA) but inherits NFS semantics; can configure stricter modes

# Key Implications

If your application requires strict POSIX semantics (e.g., databases with byte-range locking, build systems expecting consistent metadata), NFS's close-to-open model may surprise you. Lustre, GPFS, and WekaFS provide stricter guarantees but at the cost of lock traffic and potential contention. For read-mostly workloads or applications that don't share files between processes, NFS's relaxed model often suffices. For how each filesystem caches data and keeps it consistent—what lives in the page cache versus the client's own memory—see Caching Across Network Filesystems.

# Architecture, Scaling & Performance

Architecture determines how systems scale and where bottlenecks emerge. Single-server designs (NFS) are simple but limited by one machine's resources. Distributed designs (Lustre, GPFS, WekaFS) scale out but introduce complexity. Understanding these trade-offs helps you predict performance for your workload.

FS Architecture Performance Profile Scaling Limits
NFS Single server
All ops to 1 box
Good: General-purpose workloads
Moderate: Metadata (5-10K ops/s)[8]
Poor: Highly concurrent small files
Single server CPU/IO
Network bandwidth
Typical: 100s clients
Lustre MDS + OSTs
Separated meta/data
Excellent: Large files (100+ GB/s), parallel I/O across OSTs
Poor: Small files (metadata bound), millions of files in one dir
MDS metadata ops [9]
Single MDS: ~20K ops/s
Multi-MDT helps but adds complexity
Scales to 1000s clients
GPFS Shared disk
Distributed token mgmt
Good: Mixed workloads
Excellent: Metadata (50K+ ops/s)[10], random I/O
Good: Small and large files
Network fabric
Token contention under heavy write sharing
Scales to 1000s clients
WekaFS Fully distributed
Coherent cache everywhere
Excellent: Small files, metadata (millions of ops/s) [11], low latency (sub-ms)
GPU-direct, RDMA-capable
Designed for massive scale (1000s clients)
Requires high-speed network (100GbE+)
VAST DASE: separated compute (CNode) from storage (DBox) + NVMe-oF Excellent: AI/ML workloads [12], mixed read/write patterns
Good: Global dedup/compression, simpler ops than Lustre/GPFS
Network fabric size
Write cache fill under sustained high I/O
Scales to 1000s clients

[8]  NetApp NFS performance guide TR-4067; typical enterprise server
[9]  Lustre Operations Manual 2.15; single MDT performance limits
[10] IBM GPFS Performance Tuning Guide; large enterprise deployment
[11] Weka technical documentation; AI/ML workload benchmarks
[12] VAST Data technical documentation; designed for AI-era workloads with high concurrency

# Workload Matching

Architecture dictates performance sweet spots. Match your workload to filesystem strengths:

  • Deep learning training: Millions of small image files > WekaFS's distributed cache and metadata performance excel, while NFS would crawl under metadata load.
  • Genomics pipelines: Terabyte-scale files, sequential I/O > Lustre's parallel data paths across multiple OSTs shine, delivering 100+ GB/s aggregate throughput.
  • Mixed enterprise workloads: VMs, databases, home directories > GPFS or NFS offer good balance for varied access patterns without extreme specialization.
  • HPC checkpointing: Periodic massive writes from thousands of ranks > Lustre (if you can tolerate load shedding) or GPFS (better reliability but lower peak throughput).

# Failure Modes & Overload Behavior

Systems fail. Clients misbehave. Loads spike. How filesystems handle these scenarios determines whether you experience graceful degradation or catastrophic failure. Understanding failure modes is essential for production deployments—it's not if things break, but when and how.

FS Read Overload Write Overload Server Failure
NFS Slow responses
Queue on server
Graceful degradation
Clients hang [13]
RPC timeout (default: 60s, retries = forever)
Hard-mount calls retry while the server is unavailable and may remain blocked until recovery
Lustre Client throttling
Read-ahead reduced
Performance degrades
Load shedding! [14]
OST silently drops writes - app sees success but data lost. Check logs!
MDS fail: all metadata stops (open/stat/mkdir)
OST fail: only files on that OST affected
No transparent failover
GPFS Token contention
Increased latency
Caching helps absorb
Write-behind fills
Graceful throttling
Blocks when full
No data loss
Fast recovery (5-30s)
Distributed recovery protocol [15]
Quorum-based HA
WekaFS Distributed cache absorbs read bursts
Maintains low latency
Intelligent throttling
Maintains latency targets
Fast failover (~10s)
Distributed replicas
No single point of failure
VAST All-flash backend handles read bursts
NVMe-oF low latency
Write buffer (SCM) in DBoxes can fill
Performance drops to backend speed
CNode fail: stateless, clients reconnect [16]
DBox fail: erasure-coded, auto-rebuild

[13] NFS hang behavior infamous in HPC; "the NFS hang of death"
[14] Lustre load shedding: OST silently discards writes under overload; write() succeeds but data never reaches disk. Only detectable via OST logs (search for "ENOSPC" or drop messages). Catastrophic for applications assuming POSIX write semantics.
[15] GPFS recovery protocol: "Scalable cluster-wide failure recovery" (FAST '08)
[16] VAST CNodes are stateless; failure means clients reconnect to another CNode with no data loss

# Misbehaving Client Scenarios

What happens when a client crashes mid-write while holding locks?

  • NFS: Server detects client timeout (typically 90s), releases locks, continues. Other clients may see partial writes if data wasn't flushed. NFSv4 improves with lease-based recovery.
  • Lustre: LDLM has lock recovery protocol. If client crashes with dirty data, that data is lost (client-side caching). Lock timeout ~20s, other clients can proceed. Corruption possible if application didn't fsync().
  • GPFS: Token manager detects node failure via heartbeat, forcibly revokes tokens, performs recovery. Strong consistency maintained. Recovery typically completes in seconds for small failures.
  • WekaFS: Distributed consensus detects failure, invalidates client's cache, reassigns ownership. Replica ensures no data loss. Other clients continue with minimal disruption.
  • VAST: NFS-based recovery—server detects client timeout and releases locks. CNodes are stateless, so no server-side dirty data to lose. Client reconnects to another CNode transparently. Data in DBoxes is erasure-coded and unaffected by client or CNode failures.

# Real-World Implications

Lustre's silent data loss: Under sustained write overload, Lustre OSTs can silently drop writes while reporting success to the application. Your write() returns successfully, but data never reaches disk. The only indication is cryptic messages in OST logs. For critical workloads, you must implement application-level checksumming or verification, and monitor OST logs for drop messages. This violates POSIX expectations and has caused data loss in production HPC systems.

NFS blocking: With hard-mount retry behavior, filesystem calls can remain blocked while the server is unreachable and can stall dependent workers. Treat that as an application-availability concern: isolate NFS-dependent work, use safe deadlines at application or workflow boundaries, monitor blocked operations, and define recovery behavior. Choose retry semantics from explicit correctness and data-handling requirements rather than treating a mount option as a simple consistency-versus-availability switch.

GPFS, WekaFS, and VAST: Provide better resilience with fast recovery and no silent data loss, but at higher cost. VAST trades some POSIX strictness for operational simplicity (NFS-based client access), while GPFS and WekaFS offer full POSIX compliance at greater complexity. All three require significant infrastructure investment.

⚠ Object Storage: AWS S3 (Not a Filesystem)

Direct Amazon S3 is an object-storage API, not a POSIX filesystem. General-purpose buckets use a flat key namespace; directory buckets add hierarchical directories, but both remain object APIs with semantics different from POSIX filesystems. S3 is ubiquitous in cloud environments, and FUSE bridges (s3fs, goofys) attempt to make its object API appear as a filesystem. Understanding the mismatch is critical.

Key differences and common pitfalls:

  • Rename depends on bucket type: General-purpose buckets implement rename as copy + delete, which is not atomic across the two operations. S3 Express One Zone directory buckets support atomic RenameObject for an individual object within the same directory bucket.
  • No true "list directory": S3 only lists objects with a prefix. Listing a "directory" with millions of objects is slow (charged per 1000 list requests) and can take minutes. A simple ls that takes milliseconds in POSIX can cost dollars and time in S3.
  • Append is limited: General-purpose buckets do not provide in-place append. S3 Express One Zone directory buckets support append with x-amz-write-offset-bytes (up to 5 GB per request and 10,000 total parts). Other designs must create a replacement object, though server-side multipart copy can avoid downloading the entire source.
  • No general in-place random updates: PutObject replaces a whole object; S3 does not expose POSIX-style byte-range mutation. Range reads and multipart copy can reduce client transfer, but databases that require in-place random writes still do not map directly to the object API.
  • Object-level permissions via IAM, not POSIX: No chmod or chown. Permissions managed via IAM policies and bucket ACLs. Multi-user Linux scenarios don't map cleanly.
  • No hardlinks or symlinks: Every object is independent. Can't create efficient directory structures or file aliases.
  • Strong per-key object consistency: After a successful object PUT or DELETE, subsequent GET and LIST requests are strongly consistent; replacement of one key is atomic, so readers receive the old or new object rather than a partial object. S3 still lacks POSIX byte-range mutation, cross-key transactions, and shared-file locking semantics.

When S3 makes sense: Immutable data (backups, archives, media files), write-once-read-many workloads, bulk storage where cost matters more than performance. Avoid for: databases, logs with frequent appends, applications expecting POSIX semantics. FUSE bridges help for read-heavy workloads but have severe write limitations—use with caution and test your assumptions.