FaRM: Fast Remote Memory

cluster farm-nsdi14
RDMAdistributed-memoryone-sided-RDMAlock-free-readskey-value-storehopscotch-hashing

§1 TL;DR #

FaRM is an RDMA-based distributed computing platform that exposes cluster memory as a shared address space with ACID transactions, achieving 10x throughput and 100x lower latency than TCP/IP via one-sided RDMA lock-free reads and RDMA-write messaging.

§2 Q1 / Q2 / Q3 #

Q1 痛点 #

Main-memory distributed systems bottleneck on TCP/IP networking: a state-of-the-art key-value store (MemC3) performs 7x worse in a client-server TCP/IP setup than in a single-machine setup, despite extensive request batching. DRAM prices have dropped enough that a 100-machine cluster can hold tens of terabytes in main memory, but the network stack — not memory — is the performance ceiling.

Q2 方法 #

FaRM builds three interlocking mechanisms on top of RDMA:

  1. RDMA-write circular-buffer messaging — sender writes to a pre-allocated receiver-side ring buffer via one-sided RDMA writes; receiver polls head for new messages. Achieves 9–11x higher request rate than TCP/IP for 16–512 byte messages.
    1. Lock-free one-sided RDMA reads with cache-line versioning — each object carries a header version and per-cache-line versions. A reader issues a single RDMA read and validates that all versions match and the lock bit is clear. Strict serializability follows from x86 cache-coherent DMA ordering guarantees. This doubles throughput over RDMA messaging for read-dominated workloads.
      1. Locality optimizations — collocation hints in txAlloc place related objects on the same machine; function shipping converts distributed transactions into single-machine transactions (only a commit message to replicas, no prepare/validate round-trips).
      2. Supporting infrastructure: PhyCo kernel driver allocates physically-contiguous 2 GB regions to collapse NIC page tables from >500K entries to 1; NUMA-aware queue pair multiplexing ($q$ threads share one connection) prevents NIC cache thrashing as cluster scales.

        核心技术壁垒: the cache-line versioning scheme that delivers strictly serializable lock-free reads via a single RDMA read without involving the remote CPU. Correctness relies on three non-obvious hardware properties: (a) RDMA writes are performed in increasing address order, (b) DMA is cache-coherent on x86, and (c) compiler barriers on x86 enforce sufficient ordering for DMA-visible memory writes. Replicating this on non-x86 platforms requires re-deriving the memory ordering guarantees, and achieving the same single-RDMA-read property demands per-cache-line version metadata layout with careful space/wrap-around trade-offs.

        Q3 结果 #

        • 146M key-value lookups/s at 35 µs latency on 20 machines (uniform), 10x throughput and 100x lower latency than TCP/IP baseline
        • 126M graph ops/s at 41 µs on a Tao-like workload (10x per-machine throughput vs reported Tao numbers)
        • 1.04 RDMA reads per lookup at 90% occupancy (vs 3.2 for cuckoo-based Pilaf)
        • Flat combining improves hot-key throughput by >4x under YCSB skew

        §3 架构 / 方法图 #

        flowchart TB subgraph Cluster["FaRM Cluster (20 machines, 40 Gbps RoCE)"] subgraph M1["Machine 1"] T1["Pinned Threads\n(event loop)"] SM1["Shared Memory\n100 GB (2 GB PhyCo regions)"] NIC1["Mellanox CX-3\nRoCE NIC"] SSD1["SSD (logging)"] end subgraph M2["Machine N"] T2["Pinned Threads"] SM2["Shared Memory\n100 GB"] NIC2["RoCE NIC"] SSD2["SSD"] end end subgraph AddrSpace["Shared Address Space"] RMAP["Region Map\n(consistent hashing,\nk=100 virtual rings)"] ALLOC["3-level Allocator\nRegion → Block → Slab"] end subgraph DataPath["Data Path"] LFR["Lock-free Read\n(1 RDMA read +\nversion check)"] MSG["RDMA-write Messaging\n(circular buffer)"] TX["Distributed Tx\n(OCC + 2PC via RDMA msg)"] SMTX["Single-machine Tx\n(function ship +\ncollocation)"] end T1 --> LFR T1 --> MSG T1 --> TX T1 --> SMTX LFR -->|"one-sided RDMA read"| NIC2 MSG -->|"RDMA write to ring buf"| NIC2 NIC2 --> SM2 TX -->|"prepare / validate / commit"| NIC2 SMTX -->|"commit msg only"| NIC2 SM1 --- RMAP SM2 --- RMAP

        FaRM machines are both data stores and compute nodes. Each machine registers its 100 GB shared memory as 2 GB PhyCo regions with the NIC, enabling single-entry page tables. The shared address space uses a 64-bit address (32-bit region ID + 32-bit offset) resolved locally via consistent hashing on $k = 100$ virtual rings.

        Two data paths serve different access patterns: lock-free one-sided RDMA reads for read-only operations (single RDMA, no remote CPU involvement), and RDMA-write messaging for transactions and function shipping. The transaction protocol uses OCC with 2PC for distributed transactions, but applications can opt into single-machine transactions when data is collocated, eliminating the prepare and validate phases.

        Object versioning layout #

        flowchart LR subgraph OBJ["Object (spans multiple cache lines)"] direction TB CL0["Cache Line 0\n[Incarnation | Lock | V_obj | ... data ...]"] CL1["Cache Line 1\n[V_c1 | ... data ...]"] CL2["Cache Line 2\n[V_c2 | ... data ...]"] end CHECK["Lock-free Read\nValid iff:\nL = 0 AND\nV_c1 ≡ V_obj (mod 2^l)\nV_c2 ≡ V_obj (mod 2^l)"] OBJ --> CHECK

        The reader issues a single RDMA read spanning the entire object. If the header version is unlocked and its low-order $l$ bits match all cache-line versions, the snapshot is consistent. Mismatch triggers retry with randomized backoff.

        §4 作者证明 #

        无形式化作者证明 — 仅实证。The paper contains no numbered equations and no formal model; all claims are validated empirically.

        非形式化正确性论证 #

        Lock-free read serializability argument (§3.5): the paper argues that a lock-free read returning matching versions across all cache lines is strictly serializable with concurrent transactions.

        1. Transaction commit writes cache-line versions in a specific order: (a) write special lock value to cache-line versions, (b) update data in each cache line, (c) update cache-line versions and header version — separated by memory barriers.
        2. On x86, compiler barriers suffice because DMA is cache-coherent — any RDMA read observes memory writes within each cache line in barrier-enforced order.
        3. RDMA writes are performed in increasing address order (NIC hardware guarantee).
        4. Therefore, if an RDMA reader sees matching unlocked versions across all cache lines, the read observes a consistent snapshot from a single committed state.
        5. Assumption inventory:

          #AssumptionWhere relied upon
          1RDMA writes in increasing address orderLock-free read correctness (§3.5)
          2Cache-coherent DMA on x86Lock-free read correctness (§3.5)
          3Crash failures only (no Byzantine)Transaction correctness (§3.2)
          4Bounded clock driftZooKeeper leases, version wrap-around safety (§3.5)
          5Bounded max simultaneous failures per replica groupAvailability guarantee (§3.2)
          6Eventual synchronyLiveness guarantee (§3.2)

          Bandwidth budget:

          40 Gbps RoCE = 5 GB/s per NIC. With 16-byte keys + 32-byte values (≈128 bytes per bucket-pair RDMA read), theoretical NIC bandwidth supports $5 \times 10^9 / 128 \approx 39\text{M reads/s}$ per machine. Observed 7.3M lookups/machine (146M ÷ 20), well below this ceiling — the bottleneck is packet rate, not bandwidth, consistent with Figure 2 showing packet-rate saturation at small transfer sizes.

          Scaling: throughput scales linearly with machine count for uniform workloads (near-zero coordination for lock-free reads). For skewed workloads, NIC saturation on hot-key machines limits scaling beyond ~8 machines.

          §5 实验与数据 #

          5.1 Communication primitive micro-benchmarks #

          RDMA vs TCP/IP throughput (Figure 2): RDMA messaging delivers 9–11x higher request rate than TCP/IP for 16–512 byte transfers. One-sided RDMA reads add another 2x for sizes ≤256 bytes (half the packets). Both saturate at ~33 Gbps for ≥2 KB sizes.

          Latency (Figure 3): at peak load, TCP/IP latency is ≥145x higher than RDMA messaging across all request sizes. Unloaded RDMA read latency is ≥12x lower than TCP/IP and 3x lower than RDMA messaging.

          PhyCo impact (Figure 4): without PhyCo, RDMA request rate drops 4x when registered memory exceeds 16 MB due to NIC page table cache thrashing. PhyCo sustains constant rate up to 100 GB.

          Connection multiplexing (Figure 5): optimal sharing factor $q$ varies with cluster size — small $q$ provides more parallelism (better for small clusters), large $q$ reduces queue pair pressure (necessary for larger clusters).

          5.2 Key-value store performance #

          MetricFaRM (20 machines)TCP/IP baselineRatio
          Lookup throughput (uniform)146M ops/s13.8M ops/s10.6x
          Lookup throughput (YCSB)103M ops/s
          Lookup latency (uniform, peak)35 µs8000+ µs>228x
          TCP latency at 1 ms target3.8M ops/sFaRM 38x
          Single-machine throughput26M ops/s40M ops/s0.65x
          RDMAs per lookup (90% occ)1.04

          FaRM's single-machine throughput is 35% lower than the baseline because its general lock-free read support copies objects even locally. The advantage materializes at scale.

          Update workloads (5% updates, YCSB-B): FaRM with SSD replication achieves 10x higher throughput than the non-replicated TCP/IP baseline. SSD logging adds 30% overhead vs no replication. SSDs become the bottleneck at >5% update rate (215 MB/s writes + 215 MB/s cleaning reads saturate I/O bandwidth).

          Optimization contribution breakdown (§4.2): low-level RDMA tuning (PhyCo + multiplexing) → 8x; lock-free one-sided reads vs messaging → 2x; hopscotch hashtable vs Pilaf's cuckoo design → 3x fewer RDMAs per lookup.

          5.3 Tao graph store #

          126M graph ops/s at 41 µs on 20 machines. Per-machine throughput is 10x reported Tao numbers; latency is 40–50x lower. Three dominant operations (85% of workload) each require only 1.02 RDMA reads on average via lock-free reads of collocated edge lists.

          5.4 Hashtable design space #

          Inlining values with $H = 8$ or $H = 6$ provides good throughput/space balance for objects ≤128 bytes. $H = 2$ maximizes throughput at the cost of space utilization. Objects >320 bytes should be stored out-of-table with pointers in buckets.

          §6 论证链 #

          StepClaimEvidenceDepends on
          1TCP/IP is the bottleneck for main-memory distributed systemsMemC3 shows 7x single-machine vs distributed gap despite batching [16]
          2RDMA writes can implement high-performance messaging via circular buffersMicro-benchmark: 9–11x throughput over TCP/IP, ≥145x lower latency at peak (Figures 2–3)Step 1
          3One-sided RDMA reads add 2x throughput for read-dominant workloads by halving packet countAdditional 2x for sizes ≤256 bytes (Figure 2); reads bypass remote CPU entirelyStep 2
          4Lock-free reads via cache-line versioning are strictly serializable with transactionsInformal proof: x86 DMA cache coherence + RDMA write ordering + memory barriers guarantee consistent snapshots (§3.5)Step 3
          5NIC resource pressure must be actively managed at scalePhyCo eliminates 4x degradation (Figure 4); connection multiplexing optimizes queue pair caching (Figure 5)Steps 2–3
          6Chained associative hopscotch hashing achieves near-single-RDMA lookups at high occupancy1.04 RDMA reads/lookup at 90% occupancy vs 3.2 for Pilaf (§3.6); joint versioning extends lock-free reads to bucket pairsSteps 3–4
          7Collocation + function shipping convert distributed transactions to single-machine transactionsEliminates prepare/validate phases; Tao edge lists collocated with source nodes achieve 1.02 RDMA reads/op (§4.4)Steps 4, 6
          8End-to-end: 10x throughput and 100x lower latency vs TCP/IP146M lookups/s at 35 µs; 126M graph ops/s at 41 µs (Figures 12, §4.4)Steps 2–7

          §7 实现 cross-reference #

          [实现未公开] — FaRM is a Microsoft Research internal system with no public source code.

          核心技术壁垒详解 #

          The cache-line versioning scheme (§3.5) is the hardest-to-replicate component. Reimplementation requires:

          1. Per-cache-line version metadata layout: each cache line (except the first) begins with a truncated version number ($l$ low-order bits of the 64-bit header version, where $l = 16$). Space overhead is 2 bytes per cache line.
            1. Three-phase write protocol with barriers: (a) write lock value to all cache-line versions, (b) update data in each cache line, (c) write new versions to cache lines and header. On x86, compiler barriers (asm volatile("" ::: "memory")) provide sufficient ordering because DMA is cache-coherent.
              1. Read validation: after the single RDMA read completes, check that the header version is unlocked and its low-order $l$ bits match every cache-line version. Any mismatch triggers retry with randomized backoff.
                1. Wrap-around safety: 16-bit cache-line versions require that no RDMA read spans two successive writes producing identical low-$l$-bit versions. This is guaranteed by bounding write duration relative to read duration, relying on the bounded clock drift assumption.
                2. 关键实现细节 #

                  1. PhyCo 2 GB regions: commodity OS large page support (even 2 MB) was insufficient — NIC page table caches still thrashed. FaRM implemented a custom kernel driver allocating physically-contiguous, naturally-aligned 2 GB regions at boot and modified the NIC driver to use 2 GB page table entries. This is a boot-time, OS-level intervention not achievable with standard APIs.
                    1. Joint versioning for adjacent hashtable buckets: lookups read two adjacent bucket objects with a single RDMA. Mutual consistency is ensured via forward/backward joint version pairs — each bucket stores both a forward version (shared with next bucket) and a backward version (shared with previous bucket). Any RDMA-aware data structure that reads multi-object neighborhoods must solve this mutual-consistency problem.
                      1. Flat combining for hot keys: concurrent inserts/updates to the same key are combined into a single transaction, yielding >4x throughput improvement under YCSB skew ($\theta = 0.99$). Without this, hot-key contention dominates even with RDMA-speed lock/unlock cycles.
                      2. Software → hardware implications #

                        FaRM's design implicitly argues for several NIC/fabric features:

                        • Large page support in NIC page tables: 2 GB entries eliminate page table cache pressure; without them, performance degrades 4x at >16 MB registered memory
                        • RDMA write ordering guarantees: lock-free read correctness depends on increasing-address-order writes; relaxing this guarantee invalidates the consistency model
                        • Cache-coherent DMA: required for the compiler-barrier-only memory ordering strategy
                        • Dynamically Connected Transport: would solve queue pair scalability without application-level multiplexing hacks
                        • RDMA batching: absence of NIC-level RDMA batching prevents multi-get implementation, leaving a 3x gap vs TCP/IP with multi-get of 100 keys