Scaling Training Data Storage for Next-Generation Recommender Systems with User Sequences

meta · Tech · 2023 · source Agentic: no · promotional bias: low · source-backed · extracted with prompt 0.5.6 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: AI training data storage for recommender systems

Meta needed to store much longer user-sequence features for next-generation recommenders without letting duplicated training rows explode storage, power, latency, and GPU-training cost.

Constraints:

Architecture

Meta normalized training data by splitting lightweight training rows from a separate user-sequence table stored in ZippyDB. A special training-preprocessor connector joins rows and sequences at training time, while storage-server optimizations such as offloaded SSTable compaction, direct SSTable loading, RocksDB multi-scan, and schema-aware projection reduce write amplification, read latency, and over-fetching.

Diagram confidence: reconstructed (reconstructed from prose).

flowchart LR
  A["Training table"] --> D["Training preprocessor connector"]
  B["User sequence table"] --> C["ZippyDB sequence store"]
  C --> D
  D --> H["GPU training jobs"]
  E["Direct SSTable load pipeline"] --> C
  F["RocksDB multi-scan layer"] --> C
  G["Schema-aware projection layer"] --> C
  G --> H
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
Training table Warehouse-backed warm-storage table holding lightweight training rows and sequence references. Training preprocessor connector
User sequence table Separate table containing user sequences addressed by unique sequence IDs. ZippyDB sequence store, Training preprocessor connector
ZippyDB sequence store Distributed key-value storage used as efficient indexable storage for point lookups. User sequence table, Direct SSTable load pipeline, RocksDB multi-scan layer, Schema-aware projection layer, Training preprocessor connector
Training preprocessor connector Joins training rows with referenced user sequences and reconstructs samples for training. Training table, User sequence table, ZippyDB sequence store, GPU training jobs
Direct SSTable load pipeline Pre-generates and compacts SSTables outside the serving database to reduce write and read amplification. ZippyDB sequence store
RocksDB multi-scan layer Coalesces and parallelizes batch scans so latency is bounded by the slowest scan rather than the sum of serial scans. ZippyDB sequence store
Schema-aware projection layer Filters sequence events, attributes, and time ranges before data reaches the GPU side. ZippyDB sequence store, GPU training jobs
GPU training jobs Training consumers that need reconstructed samples without stalls or unnecessary sequence payload. Training preprocessor connector, Schema-aware projection layer

Data flow

Training rows remain in a warehouse-backed training table with lightweight references; user sequences move to a ZippyDB-backed indexable table keyed by sequence ID; the training preprocessor uses a special connector to join rows and sequences at training time; optimized SSTable loading, multi-scan reads, and schema-aware projection make the storage server efficient enough to feed GPU training jobs.

3 supporting quotes
“training rows with lightweight references to keys in the user sequence table continues to remain on warehouse backed by warm storage HDD.”transcript, stated
“The user sequence table is moved to an efficient indexable storage since the access pattern we expect on this table to be point lookups.”transcript, stated
“needed a special connector that does a join between the training table and the user sequence table to reconstruct these training samples at the time of training.”transcript, stated

Why this architecture

The self-contained-row model made training-sample reconstruction simple but duplicated slowly-changing user features. Meta accepted a more complex join architecture because normalization could cut duplication, then optimized storage reads and preprocessing enough to make the split-table design cost-effective.

3 supporting quotes
“This makes it very easy to reconstruct the training sample at the time of training because all we need to do is read the training row and nothing else.”transcript, stated
“However, there's a downside with this approach, which is data duplication.”transcript, stated
“The entire solution becomes cost effective only if we are able to optimize these joins”transcript, stated

Scale

Alternatives considered (roads not taken)

Keep fully self-contained training rows

Rejected because: Self-contained rows were easy to reconstruct but duplicated user-sequence data heavily as sequences grew.

“Our previous data model for training relied on fully self-contained rows.”transcript, stated
“However, there's a downside with this approach, which is data duplication.”transcript, stated

Store user sequences inline in every training row

Rejected because: Meta split user sequences into a separate table and kept lightweight references in the training table.

“Rather than storing all of the training data in a single table, we split the data into two tables.”transcript, stated
“store a lightweight pointer to the rows in the sequence table.”transcript, stated

Use row-by-row insertion into ZippyDB

Rejected because: Row inserts triggered compaction and write-path overhead, so Meta built direct SSTable loading from external pipelines.

“When we populate the initial storage, we used the row by row insertions.”transcript, stated
“direct load pre-generated SSTables from external completely bypassing the expensive memtable and the write-ahead logs”transcript, stated

Execute sequence scans serially

Rejected because: Serial scans made latency the sum of all scans, so Meta added a native multi-scan API and parallel IO.

“the scans were executed in serial. This was because RocksDB doesn't support native multiple scans and ZippyDB had to do the scans serially.”transcript, stated
“When a batch of reads are received via a new multi-scan API”transcript, stated

Fetch entire sequences and filter on the GPU side

Rejected because: Over-fetching increased network, CPU, and latency tax, so Meta filtered by schema, attributes, and time ranges earlier.

“If this knowledge was not leveraged, we need to fetch the entire sequence back to GPU and then filter the out uninterested data on the GPU side.”transcript, stated
“feature projection to filter out uninterested event attributes after decoding the key values.”transcript, stated

Patterns

batch-offline-processing (data-infrastructure)

Meta moved expensive compaction, optimization, indexing, and SSTable generation into external data pipelines before loading optimized files into serving storage.

“we introduced a new API that allows direct load pre-generated SSTables from external completely bypassing the expensive memtable and the write-ahead logs”transcript, stated
“we are able to build data pipelines to periodically compact, optimize, and index data outside of the VDDV servers.”transcript, stated

Tradeoffs

Normalize training data into two tables.

Chose separate training rows and user-sequence rows over fully self-contained training rows.

Rationale: The split reduced duplication but required more complex on-the-fly reconstruction during training.

“Rather than storing all of the training data in a single table, we split the data into two tables.”transcript, stated
“there is a trade-off over here. And the trade-off is there is a more complex training sample reconstruction.”transcript, stated

Move user sequences to ZippyDB.

Chose efficient indexable key-value storage over keeping sequence payloads inline in the warehouse-backed training table.

Rationale: The expected access pattern was point lookups by sequence ID.

“The user sequence table is moved to an efficient indexable storage since the access pattern we expect on this table to be point lookups.”transcript, stated
“We decided to leverage ZippyDB, which is a widely used distributed key-value store within Meta”transcript, stated

Build storage-specific optimizations instead of abandoning the normalized design.

Chose SSTable direct load, multi-scan, and schema-aware projection over returning to the original single-table training data layout.

Rationale: The first normalized implementation was costly, but targeted optimizations made it practical and efficient.

“we had to land a lot of optimization on both the training preprocessor side and the storage server side to make sequence storage cost-effective and practical.”transcript, stated

Gotchas (what bit them)

Normalizing training data reduced duplication but made sample reconstruction harder.

Root cause: The training preprocessor now had to join training rows with separate user-sequence rows during training.

Resolution: Meta built a special connector and optimized the join and storage server path until the split-table design became cost-effective.

“there is a trade-off over here. And the trade-off is there is a more complex training sample reconstruction.”transcript, stated
“the training preprocessor needs to do join reading a training row from the training table and the user sequence from the user sequence table”transcript, stated

The first ZippyDB-backed version was not cheaper than the original design.

Root cause: ZippyDB had not been optimized for training workloads, and the preprocessor had more complex reconstruction work.

Resolution: Meta optimized both the training preprocessor side and storage server side.

“the overall system turned out to be as costly or if not more as the original approach of storing all of the data in a single table.”transcript, stated
“ZippyDB was never used for training workloads, and most of the optimizations over there were for mostly OLTP-ish like workloads.”transcript, stated

Row-by-row insertion caused storage-server read amplification and write pressure.

Root cause: Frequent background compactions and multi-level log-structured tree traversal consumed server resources and flash IO.

Resolution: Meta generated optimized SSTables externally and loaded them directly into the storage server.

“we observed that this triggered the frequent background compactions in RocksDB.”transcript, stated
“Every single read now is only served from a single SST table file. We pretty much achieved one IO per read.”transcript, stated

Serial scans caused GPU pipeline stall risk.

Root cause: RocksDB did not support native multiple scans, so ZippyDB scans were serial and total latency summed across scans.

Resolution: Meta implemented a native multi-scan API that coalesced adjacent IO and issued ranges in parallel.

“the total latency was the sum of all individual scans. This high latency led to training GPU QPS regression risks”transcript, stated
“After identifying the coalesced ranges, we issue those IOs in parallel against these ranges.”transcript, stated

Opaque key-values caused over-fetching.

Root cause: Models often needed only specific time ranges and attributes, but the old path fetched whole sequences and filtered on the GPU side.

Resolution: Meta made the query engine schema-aware and added feature projection and length truncation.

“Most of our models only needs to access interested events within certain time ranges and a subset of event attributes instead of all the attributes.”transcript, stated
“Both optimizations in combination reduced the data to be fetched from GBDV to about 1/3 compared to the original situation.”transcript, stated

Evaluation

Meta evaluated the design through storage-server efficiency, read throughput, sequence length supported, data fetched, read IO count, and production adoption across models.

Metrics: storage server efficiency · read throughput per server · events per user sequence · data fetched compared with original approach · production models served · IO per read

3 supporting quotes
“We pretty much achieved one IO per read.”transcript, stated
“Both optimizations in combination reduced the data to be fetched from GBDV to about 1/3 compared to the original situation.”transcript, stated
“We ended up with a storage server that was roughly 5x more efficient than when we started.”transcript, stated

Outcomes

The work addressed training data at tens-of-exabytes scale across more than 10 data centers and 10% of Meta's power budget.

3 supporting quotes
“support more than a gigabyte per second read throughput up from 200 megabytes per second when we started.”transcript, stated
“scale the user sequence length from 2K events to 80K events, which is almost a 40x improvement”transcript, stated
“Sequence storage is currently in production serving 30 plus models across various product groups.”transcript, stated