Docs
Using Dista
Dista turns ordinary Mojo functions into tasks that run across a cluster. One binary runs as the driver, the head and every worker, on a laptop or on Kubernetes. This page installs it and runs a first program; the pages below cover the rest. How it works is in the repository's DESIGN.md.
The docs
- Tasks and results: Declaring tasks, where results live and how they're freed, tasks on other tasks' results, cancelling and timeouts, and what crosses the wire.
- Shuffles: Tasks with several results, tasks taking a value beside results, placement by data location, and spilling.
- Actors and checkpoints: State on a worker of its own, handles passed to tasks, restarts, checkpoints, and actors moving off a draining worker.
- Running a cluster: Roles from the environment, the generic head, Kubernetes and EC2, draining a worker, and autoscaling.
- The dista command: dista head, status, drain, scale, timeline and stop; Prometheus metrics; the task timeline.
- Failure and recovery: What happens when a task raises, a worker dies or goes silent, a task hangs, a driver leaves, or the head restarts.
- Tuning: Tasks in flight per worker, backpressure, the node store and spilling, memory held for drivers, and large results.
Install it
Dista is the mojoshelf tin dista-mojo, version 0.2.2. With pixi and
mojoshelf's pixi shelf installed, a new project adds it, and the tins it
needs (arrow-mlake, memory-region and objectstore) come with it:
pixi init -c https://conda.modular.com/max-nightly -c conda-forge app && cd app
sed -i.bak 's/^\[workspace\]/[workspace]\npreview = ["pixi-build"]/' pixi.toml # tins build with pixi-build
pixi add "mojo-compiler==1.2.0"
pixi shelf add dista-mojo
It targets Mojo 1.2.0, and its CI also runs on the 1.3 nightly. Reading Parquet and
Iceberg tables in tasks uses magmalake's parquet-mojo and
iceberg-mojo beside it.
A first program
A task is a top-level def, declared once with its argument and result
types, and registered in the runtime's parameter list:
from dista import ObjectRef, Runtime, Task
def square(x: Int) -> Int:
return x * x
comptime Square = Task[Int, Int, square]
def main() raises:
var rt = Runtime[Square](workers=4)
var refs = List[ObjectRef[Int]]()
for i in range(1000):
refs.append(rt.remote[Square](i))
var total = 0
for r in refs:
total += rt.take(r) # get and release: read once, then freed
print(total) # 332833500
Build it with mojo build and run it. With nothing set in its environment,
it forks a head and four workers on this machine and drives them. Point the same
binary at a head and it joins a cluster instead:
DISTA_ROLE=head DISTA_PORT=6390 ./app # the head
DISTA_ROLE=worker DISTA_HEAD=headhost:6390 ./app # once per worker
DISTA_HEAD=headhost:6390 ./app # the driver Tasks and results says what a task can take and return, and Running a cluster how the roles fit together.
From source
The repository builds and tests with pixi. pixi run cli builds the
dista command to build/dista.
git clone https://github.com/magmalake/dista.mojo && cd dista.mojo
pixi run test # codec, frame, runtime and cluster tests, Mojo 1.2.0
pixi run -e nightly test # the same on the 1.3 nightly
pixi run -e data test-data # tasks over Parquet and Iceberg; needs those tins checked out next door
pixi run bench # task throughput
pixi run test-kind # the smoke test on a kind cluster (needs docker, kind, kubectl) What each release changed is in CHANGELOG.md, and what Dista is for, with its phases, in VISION.md.