Optimizing vLLM for High-Throughput Embedding Inference at Scale
snowflake · Tech · year n/a · 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: Enterprise embedding inference throughput and cost optimization
Snowflake needed Cortex AI embedding inference to support large real-time and batch workloads with high throughput, low latency, and efficient GPU utilization, but vLLM benchmarks exposed CPU-side bottlenecks that left GPUs underused.
Constraints:
- Cortex AI embedding workloads process trillions of tokens per month.
- Embedding models power semantic search, recommendations, fraud detection, Cortex Agents, Cortex Search, and Cortex Analyst.
- The production serving path uses gRPC, microservices, multi-tenant serving, multiple languages, and dynamic model swapping.
- GPU supply constraints meant A10g GPUs served embeddings while H200s were reserved for very large models.
- Optimizations had to preserve production serving requirements while improving throughput and cost.
Architecture
Snowflake profiled vLLM embedding inference, found that CPU tokenization and Protobuf serialization dominated runtime, and reworked the serving path. The optimized architecture encodes embeddings as little-endian bytes, pretokenizes input so tokenization and GPU inference overlap across requests, and runs multiple identical embedding model replicas on one GPU to use idle resources. These improvements are rolling into Cortex AI and open-sourced through Arctic Inference.
Diagram confidence: reconstructed (reconstructed from prose).
flowchart LR Embedding_requests["Embedding requests"] --> Pretokenization_stage["Pretokenization stage"] Pretokenization_stage --> vLLM_embedding_inference["vLLM embedding inference"] vLLM_embedding_inference --> Little_endian_serialization["Little-endian serialization"] vLLM_embedding_inference --> Multiple_model_replicas["Multiple model replicas"] Multiple_model_replicas --> vLLM_embedding_inference Little_endian_serialization --> gRPC_frontend["gRPC frontend"] gRPC_frontend --> Snowflake_Cortex_AI_products["Snowflake Cortex AI products"] Profiling_traces["Profiling traces"] --> vLLM_embedding_inference
Components
| Component | Role | Interacts with |
|---|---|---|
Embedding requests |
Text inputs for semantic search, recommendations, fraud detection, agents, search, and analytics workloads. | Pretokenization stage |
Pretokenization stage |
Converts strings to token IDs before GPU inference so tokenization can overlap across requests. | vLLM embedding inference |
vLLM embedding inference |
Runs embedding model inference on GPUs from pretokenized inputs. | Little-endian serialization, Multiple model replicas |
Multiple model replicas |
Runs concurrent copies of the embedding model on one GPU to use otherwise idle resources. | vLLM embedding inference |
Little-endian serialization |
Serializes embedding tensors as raw little-endian bytes to reduce gRPC response latency. | gRPC frontend |
gRPC frontend |
Production serving layer supporting multi-tenant serving, multiple languages, and dynamic model swapping. | Snowflake Cortex AI products |
Snowflake Cortex AI products |
Downstream user-facing capabilities such as Cortex Agents, Cortex Search, and Cortex Analyst. | — |
Profiling traces |
Python runtime traces and flame graphs used to locate CPU/GPU bottlenecks. | vLLM embedding inference |
Data flow
Text inputs are pretokenized before vLLM, token IDs are passed into GPU inference, embedding tensors are serialized as little-endian bytes through the gRPC service, and multiple model replicas concurrently serve requests on the same GPU to increase throughput.
3 supporting quotes
Why this architecture
Snowflake optimized around the actual bottlenecks revealed by profiling. GPU inference was only a small fraction of compute time, so better model kernels alone would not solve the problem; the serving path needed CPU serialization, tokenization, scheduling, and replica-level utilization changes.
3 supporting quotes
embed() function, which handles GPU inference, accounts for just 10% of total compute time. The remaining 90% is spent on CPU tasks”article, statedModels used: snowflake-arctic-embed-m-v1.5 · Embedding models
Scale
- Snowflake processes trillions of tokens per month for Cortex AI workloads.“Snowflake processes trillions of tokens per month across both real-time and batch workloads.”article, stated
- Profiling showed GPU inference accounted for only 10% of compute time.“The
embed()function, which handles GPU inference, accounts for just 10% of total compute time.”article, stated - CPU work accounted for the remaining 90% of compute time.“The remaining 90% is spent on CPU tasks, revealing significant overhead.”article, stated
- The Cortex production benchmark used a single A10g, FP16, 512-token inputs, batch size 96, and snowflake-arctic-embed-m-v1.5.“GPU type A single A10g Embedding model
snowflake-arctic-embed-m-v1.5Precision FP16 Input token size 512 Batch size 96”article, stated - The final Cortex configuration delivered 230,000 tokens per second.“The final configuration delivered a sustained throughput of 230,000 tokens per second.”article, stated
- Open-source benchmarking improved throughput 16x on 50-token sequences and 4.2x on 512-token sequences.“we increased throughput by 16x on short sequences and 4.2x on long sequences, while reducing cost per token 16x on short sequences.”article, stated
Alternatives considered (roads not taken)
Treat GPU inference as the main optimization target
Rejected because: Profiling showed only 10% of compute time was GPU inference and 90% was CPU overhead.
embed() function, which handles GPU inference, accounts for just 10% of total compute time. The remaining 90% is spent on CPU tasks”article, statedSend raw strings directly to vLLM
Rejected because: Sequential CPU tokenization kept the GPU idle and created bubbles in the schedule.
Use Protobuf repeated float serialization for embeddings
Rejected because: Converting Python List[float32] into repeated float format added latency in the gRPC serving path.
List[float32] to Protobuf’s repeated float format”article, statedRun a single embedding model instance per GPU
Rejected because: Embedding models often leave GPU resources idle, so concurrent replicas better utilize the same hardware.
Patterns
observability-tracing (operations)
Snowflake used runtime traces and flame graphs to find that CPU tokenization and serialization, not GPU inference, dominated embedding serving time.
cost-aware-routing (optimization)
The architecture optimizes serving cost by improving throughput per GPU and showing that higher-end GPUs can be cheaper per token when fully utilized.
latency-optimization (performance)
Snowflake targeted tokenization, serialization, and GPU idle time because those serving-path delays directly affected real-time embedding products.
model-routing (model-operations)
Snowflake allocates A10g GPUs to embedding inference and reserves H200-class GPUs for very large models, then benchmarks price-performance tradeoffs.
Tradeoffs
Serialize embeddings as little-endian bytes.
Chose Raw bytes with NumPy vectorization over Standard Protobuf repeated float serialization.
Rationale: Raw little-endian bytes avoid copying, byte-swapping, and Python per-element overhead in the gRPC response path.
Disaggregate tokenization from GPU inference.
Chose A two-stage pretokenization and inference pipeline over Sequential string tokenization inside vLLM.
Rationale: The staged design overlaps tokenization for one request with GPU inference for another, removing idle GPU bubbles.
Run multiple replicas on one GPU.
Chose Concurrent identical embedding model replicas over One model instance per GPU.
Rationale: Embedding workloads leave GPU resources idle due to shorter runtimes and CPU/data-transfer bottlenecks, so concurrent replicas increase utilization.
Gotchas (what bit them)
GPU underutilization was hidden behind apparently model-serving work.
Root cause: CPU tokenization and serialization consumed most compute time while the GPU waited.
Resolution: Profile the runtime path and optimize tokenization, serialization, and replica scheduling.
Sequential tokenization created GPU schedule bubbles.
Root cause: vLLM tokenized string prompts on CPU before launching GPU inference.
Resolution: Pretokenize inputs and pass token IDs directly so tokenization and inference overlap across requests.
gRPC serialization introduced latency in the enterprise serving path.
Root cause: Python Protobuf conversion likely hit GIL and SIMD limitations when converting embedding float lists.
Resolution: Serialize embeddings as raw little-endian bytes and use NumPy vectorization.
Evaluation
Snowflake used Python runtime traces and flame graphs to diagnose bottlenecks, then benchmarked each optimization in Snowflake Cortex on A10g and in open-source H200 comparisons against vLLM and Text Embeddings Inference.
Metrics: GPU inference only 10% of total compute time before optimization · 90% of compute time spent on CPU tasks · 3x throughput improvement in Snowflake Cortex AI · 230,000 sustained tokens per second in the final Cortex configuration · 16x higher throughput on 50-token sequences · 4.2x higher throughput on 512-token sequences · 16x cost reduction per token on short sequences
3 supporting quotes
Outcomes
- Snowflake achieved 3x throughput improvement in Cortex AI.
- The final Cortex configuration sustained 230,000 tokens per second.
- Open-source benchmarks showed 16x throughput improvement on short sequences and 4.2x on long sequences.
- Short-sequence cost per token dropped 16x.
- The vLLM-specific improvements are being open-sourced in Arctic Inference.
The reported production setting is Snowflake Cortex AI embedding inference at trillions of tokens per month, with A10g production serving and H200 open-source benchmarking.