Read Ray as a distributed execution substrate for LLM data, training, reinforcement learning, tuning, and serving: tasks, actors, objects, scheduling, ownership, and failure recovery.
Personalize this lesson
Adapt explanations and teaching visuals to your background and preferred voice.
A single LLM product can need thousands of CPU preprocessing tasks, a multi-node training job, a fleet of rollout actors, and several GPU-serving replicas. Building a separate distributed system for every stage wastes engineering time. Ray gives all of them the same small execution vocabulary.
That vocabulary is the project's main contribution. A Python function becomes a remote task, a class becomes a stateful actor, and every remote result becomes an object reference. Ray's higher-level libraries build data, training, tuning, reinforcement-learning, and serving systems from those three pieces.[1]
Traditional batch systems work well when a job is a fixed directed acyclic graph. AI workloads are often less tidy. Reinforcement-learning workers create new work after observing environments, serving routers change destinations as replicas scale, and tuning services stop trials from partial results. Dependencies appear while the program is running.
The original Ray paper targeted that mix of task-parallel and actor-based computation. It paired a dynamic execution engine with distributed scheduling and fault-tolerant storage, then showed that one interface could express workloads that previously needed separate systems.[2]
Ray Core keeps its public model compact:
| Primitive | Programmer sees | Runtime owns | Good LLM use |
|---|---|---|---|
| Task | Remote function call | Scheduling, retries, result placement | Tokenization, parsing, evaluation rows |
| Actor | Remote class instance | Placement, mailbox, process lifetime | Stateful rollout worker, model replica |
| Object reference | Future-like handle | Location, transfer, ownership metadata | Dataset block, weights, batch result |
Tasks are best for stateless work. Actors keep mutable state between calls and serialize methods by default. Object references let downstream work depend on values without forcing the driver to download those values first.[3]
The first visual follows a small request through Ray Core. The driver submits work and receives references immediately. Raylets on cluster nodes schedule workers against declared resources. Workers produce immutable objects or update actor state. The driver doesn't need to know which machine holds each result.
Here is the smallest API shape. embed.remote returns references, while the actor keeps a counter across calls:
1import ray
2
3ray.init()
4
5@ray.remote(num_cpus=1)
6def embed(text: str) -> list[int]:
7 return [len(text), sum(map(ord, text)) % 101]
8
9@ray.remote(num_cpus=1)
10class BatchLedger:
11 def __init__(self) -> None:
12 self.completed = 0
13
14 def record(self, *vectors: list[int]) -> int:
15 self.completed += len(vectors)
16 return self.completed
17
18refs = [embed.remote(text) for text in ["cache", "router", "trace"]]
19ledger = BatchLedger.remote()
20count_ref = ledger.record.remote(*refs)
21
22print(ray.get(count_ref))The expected output is 3. Ray resolves each top-level object-reference argument before the actor method runs. No explicit loop downloads each vector into the driver.
That concise code hides several contracts. num_cpus=1 is a scheduling request, not an operating-system limit. The actor's process can still allocate too much memory. The list of references preserves dependencies, but returning a giant Python object can still fill the object store. Distribution removes manual socket code; it doesn't remove capacity planning.
Each node runs a raylet. Local raylets decide whether work can run on their node and coordinate with peers when it can't. A global control service (GCS) stores cluster-level control state such as node membership and actor metadata. Workers execute user code, while the shared-memory object store holds larger immutable values.
Ray schedules logical resources. A task asking for one GPU is admitted only where one GPU slot is available. Custom resources can represent accelerator type, rack, license, or another placement constraint. The scheduler doesn't infer hidden requirements from code, so an undeclared GPU or excessive heap allocation can overcommit a node.
Placement groups reserve bundles of resources together. A tensor-parallel server might request four bundles with one GPU each and require them to be packed onto one node. A pipeline-parallel model could spread bundles across nodes. The placement strategy belongs to model topology, not to Ray alone.
An ObjectRef behaves like a future, but it also names distributed data. Small values can travel directly between processes. Larger values enter each node's shared-memory object store, where eligible local buffers can avoid another full copy. Ray transfers objects between nodes when consumers need them.
The ownership system separates object data from object metadata. A worker that creates an object reference owns its metadata even if another node stores the bytes. The NSDI Ownership paper moved this metadata away from one central bottleneck and used decentralized reference counting for low-latency fine-grained work.[4]
Ownership shapes recovery. If stored bytes disappear after a node failure, Ray can reconstruct task output from lineage. It can't recover an object created with ray.put after its owner dies, and replay assumes the generating task is deterministic and idempotent.[5]
Consider a task that charges a credit card and returns a receipt. Blind replay could charge twice. The task needs an idempotency key or an external transaction record. Ray can retry execution, but application semantics decide whether retry is safe.
Ray's libraries aren't separate cluster managers. They use Core primitives and can pass objects or actors across library boundaries.
| Library | Unit of work | LLM role | Boundary it doesn't own |
|---|---|---|---|
| Ray Data | Streaming dataset blocks | Ingest, parse, tokenize, batch inference | Model training algorithm |
| Ray Train | Distributed workers | Pretraining and fine-tuning launch | Kernel implementation |
| Ray Tune | Parallel trials | Search batch size, LR, serving knobs | Statistical validity of objective |
| RLlib | Env runners and learners | Policy learning and rollout systems | Reward correctness |
| Ray Serve | Deployments and replicas | APIs, routing, autoscaling | Attention kernel math |
Ray Data streams blocks through read, transform, shuffle, and write operators rather than materializing a whole corpus in the driver. Its batch-inference paths can keep CPU preprocessing feeding GPU replicas while backpressure limits in-flight blocks.[6]
Ray Train creates a worker group, assigns ranks, and integrates distributed training frameworks. It handles launch, environment setup, checkpoints, and failure coordination around framework code. PyTorch, DeepSpeed, or another trainer still owns gradient math and collectives.[7]
Tune represents trials as distributed work and reacts to intermediate metrics. RLlib builds rollout, learner, and replay components on actors. Their value comes from composition: the same cluster can preprocess data, launch a training group, compare trials, and publish a serving deployment without translating every asset through a new scheduler.
vLLM and SGLang optimize model execution inside an engine. Ray Serve LLM exposes OpenAI-compatible requests through OpenAiIngress. Its LLMEngine protocol lets vLLM or SGLang engines plug into LLMServer, while Ray places, scales, routes, and monitors instances.[8]
Serve deployments become actors, replicas become instances of those actors, and deployment handles connect components. An ingress deployment can expose an OpenAI-compatible API. Router policies select replicas based on queue state, session affinity, prefix reuse, or a custom rule. Autoscaling changes replica count from observed load.
For large models, one logical engine replica can span several GPU workers through tensor or pipeline parallelism. Serve LLM also supports patterns such as prefill-decode disaggregation, data-parallel attention, expert parallelism, and multi-LoRA routing. Ray coordinates resources and request movement; the configured engine remains responsible for continuous batching, PagedAttention or RadixAttention, and GPU execution.[8]
Ray is strongest when one workload crosses several machines or execution modes:
Ray offers less value for one fixed single-node script, a tiny queue with ordinary web workers, or a serving engine that already fits cleanly in one process. Distribution adds packaging, cluster, observability, retry, and resource-model costs. Use it when those costs buy real parallelism or unify multiple distributed phases.
The object store has a bounded shared-memory budget. Ray can spill objects to disk when it fills, but spilling converts a memory path into storage I/O. Worker heap memory is separate. A worker can exhaust node memory even when the object store looks healthy.
The frequent anti-pattern is ray.get on a huge list of references. That asks the driver to materialize every value at once. Process results incrementally with ray.wait, keep data in Ray Data blocks, or aggregate remotely.
Actors don't restart by default. Enabling restarts reruns the constructor; it doesn't restore mutable in-memory state. A durable actor needs an external checkpoint, replay log, or reconstruction function. Actor method retries also need idempotency.
Ray only sees declared resources. A task marked num_cpus=1 can start 32 native threads. A model actor that declares one GPU can allocate host memory sized for four. Validate actual process usage and use concurrency limits inside each actor.
The GCS is central to cluster control. Production clusters need supported high-availability configuration and cluster recovery. KubeRay can recreate nodes and clusters, but transient queues and in-process actor state still disappear. A restarted cluster isn't equivalent to an uninterrupted request stream.
A remote exception surfaces when a reference is resolved, sometimes far from submission. Task timelines, actor logs, resource views, object-memory reports, and distributed traces need correlated IDs. Keep unit logic runnable outside Ray so debugging doesn't always require a cluster.
| Strength | Why it matters | Cost paired with it |
|---|---|---|
| Small Core API | One execution model across many AI workloads | Hidden distributed behavior can surprise Python users |
| Dynamic task and actor graph | Handles serving, RL, and adaptive workflows | Harder reasoning than a fixed batch DAG |
| Shared runtime for Data, Train, Tune, RLlib, Serve | Assets and resource contracts compose | Broad surface and fast-moving integrations |
| Logical resource scheduling | Heterogeneous CPU/GPU placement | Declarations aren't hard isolation |
| Object references and locality | Avoids driver bottlenecks and extra copies | Ownership, spilling, and lineage need care |
| Open governance | Community runtime isn't tied to one hosted service | Production operations still need experienced ownership |
Ray should be compared with the right layer. Kubernetes manages containers and cluster reconciliation. Spark specializes in data-parallel processing. Celery handles task queues. vLLM and SGLang run LLM kernels and schedules. Ray can sit on Kubernetes, move data like a general runtime, queue dynamic tasks, and host vLLM engines, but it doesn't erase those systems' specialized roles.
Ray began in UC Berkeley's RISELab in 2016 and 2017. Its OSDI paper was authored by researchers including Philipp Moritz, Robert Nishihara, Stephanie Wang, Michael I. Jordan, and Ion Stoica.[2] Anyscale was founded in 2019 by Ray's creators to build a managed production platform around the open-source runtime.[9]
The project now uses open governance under the Linux Foundation's PyTorch Foundation umbrella.[10] Committers, a technical steering committee, and lead maintainers govern technical work.[11] Anyscale remains a major contributor and commercial operator, but Ray's public governance and code aren't the same thing as the hosted Anyscale product.[9]
| Field | Current project fact |
|---|---|
| Origin | UC Berkeley RISELab; the OSDI paper records the founding research team.[2] |
| Stewardship | Ray is hosted by the PyTorch Foundation under the Linux Foundation, while the project governance document defines technical authority.<a href="https://pytorch.org/projects/ray/" target="_blank" rel="noopener noreferrer" title="Ray |
| Contributor model | Contributors can become committers; committers feed a TSC and lead-maintainer structure. Authority belongs to named people and roles, not automatically to employers.[11] |
| Source license | Apache-2.0 for Ray source.[12] |
| Commercial boundary | Anyscale is the company founded by Ray's creators and operates a managed platform. Open-source Ray remains independently governed.[9][11] |
| Asset boundary | Ray's license covers runtime code, not model weights, datasets, prompts, or user artifacts moved through the object store. |
The research lineage explains today's design:
| Work | Lasting idea in Ray |
|---|---|
| Ray, OSDI 2018 | Unified tasks and actors on a dynamic distributed engine |
| Ownership, NSDI 2021 | Decentralized object metadata and reference counting |
| RLlib | Composable distributed reinforcement-learning components |
| Tune | Narrow interface between trials and search schedulers |
| Exoshuffle | Application-level control over distributed shuffle scheduling |
Only the first two are necessary to understand Core. The later projects show why a general runtime can host specialized libraries without turning every workload into one monolithic scheduler.
Start with public boundaries instead of opening scheduler internals at random:
python/ray/__init__.py and remote-function or actor decorators to see user-facing handles.Pin the repository commit while reading. Ray's library APIs and internal C++ paths move faster than its three-primitives mental model.
ray.get calls often create driver bottlenecks.Answer every question, then check your score. Score 75% or higher to mark this lesson complete.
8 questions remaining.
Ray: An AI Compute Engine
Ray Project · 2026
Ray: A Distributed Framework for Emerging AI Applications
Moritz, P., Nishihara, R., Wang, S., et al. · 2018 · OSDI 2018
What is Ray Core?
Ray Project · 2026
Ownership: A Distributed Futures System for Fine-Grained Tasks
Cheng, Y., Wang, S., Yan, C., et al. · 2021 · NSDI 2021
Object Fault Tolerance
Ray Project · 2026
Ray Data
Ray Project · 2026
Ray Train
Ray Project · 2026
Ray Serve LLM Architecture Overview
Ray Project · 2026
About Anyscale
Anyscale · 2026
Ray | PyTorch
PyTorch Foundation · 2025
Ray Project Governance
Ray Contributors · 2026
Ray Apache License 2.0
Ray Contributors · 2026
Questions and insights from fellow learners.