Distributed DataFusion is a distributed execution framework that enables DataFusion DataFrame and SQL queries to run in a distributed fashion. This project provides the infrastructure to scale DataFusion workloads across multiple nodes in a cluster.
This is an open source version of the distributed DataFusion prototype, extracted from DataDog's internal implementation and made available to the community.
- Distributed SQL Execution: Execute SQL queries across multiple nodes
- Arrow Flight Integration: High-performance data transfer using Arrow Flight
- Streaming Execution: Pipeline execution model for efficient resource utilization
- Protocol Buffers: Efficient serialization for distributed communication
- Kubernetes Support: Native integration with Kubernetes for cluster management
DataFusion Distributed implements a master-worker architecture for distributed SQL query execution:
┌────────────────────────┐
│ Client (issues SQL) │
└────────────────────────┘
│
▼
┌────────────────────────────────────┐
│ ┌───────────────┐ │
│ │ Proxy │ │
│ │ (Master) │ │
│ └───────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Worker │ │ Worker │ │
│ │ 1 │ │ 2 │ │
│ └─────────┘ └─────────┘ │
│ │
│ DataFusion Distributed Cluster │
└────────────────────────────────────┘
- Proxy (Master Node): Receives queries from clients, generates distributed execution plans, coordinates worker nodes, and streams results back to clients
- Workers: Execute assigned portions of the query plan and return results to the proxy
- Arrow Flight: High-performance data transfer protocol between nodes
- Query Planning: Distributed query planning that breaks queries into stages
- Stage Execution: Individual stages that can run on different nodes
- Kubernetes Integration: Cluster management and node discovery
- Rust 1.82 or later
- Protocol Buffers compiler (protoc)
- (Optional) Kubernetes cluster for distributed execution
If you don't have Rust installed, you can install it using rustup (the official Rust installer):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shAfter installation, restart your terminal or run:
source ~/.cargo/envInstalling Protocol Buffers Compiler (protoc)
brew install protobufVerify installation:
protoc --version# Build in debug mode
./build.sh
# Build in release mode (optimized)
./build.sh --releaseClean Rebuild: If you need to completely clean and rebuild (removes all build artifacts):
# Clean rebuild in debug mode
./clean_and_build.sh
# Clean rebuild in release mode (optimized)
./clean_and_build.sh --releaseYou can also build the project directly with Cargo (the build.rs script will automatically handle Protocol Buffer compilation):
# Build in debug mode
cargo build# Build in release mode (optimized)
cargo build --releaseClean Build Artifacts: To clean previous build artifacts before rebuilding:
# Clean all build artifacts (removes target/ directory contents)
cargo clean
# Then rebuild
cargo build --releaseNote: Both commands, build.sh script and cargo automatically invoke build.rs, which handles Protocol Buffer compilation before building the main crate. The main advantage of using ./build.sh is the user-friendly output and usage examples it provides.
Run all unit tests (fast - excludes TPC-H validation):
cargo testRun tests with output:
cargo test -- --nocaptureRun comprehensive TPC-H validation tests that compare distributed DataFusion against regular DataFusion. No prerequisites needed - the tests handle everything automatically!
# Run all TPC-H validation tests
cargo test --test tpch_validation test_tpch_validation_all_queries -- --ignored --nocapture
# Run single query test for debugging
cargo test --test tpch_validation test_tpch_validation_single_query -- --ignored --nocaptureNote: TPC-H validation tests are annotated with #[ignore] to avoid slowing down cargo test during development. They're included in the CI pipeline and can be run manually when needed.
With the code now built and ready, the next step is to set up the server and execute queries. To do that, we'll need a schema and some data—so for this example, we'll use the TPC-H schema and queries.
You need TPC-H data in Parquet format. We recommend using tpchgen-rs, known as the world's fastest open-source TPC-H data generator.
Ensure you have Rust installed (if not, run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh), then:
cargo install tpchgen-cliGenerate the TPC-H dataset scale factor 1 and save them as parquet files to /tmp/tpch_s1/:
mkdir -p /tmp/tpch_s1 && cd $_
tpchgen-cli -s 1 --format=parquet# Launch a server cluster with default settings (2 workers, /tmp/tpch_s1 data, and log files in current folder)
./scripts/launch_tpch_cluster.sh
# Launch a server cluster with custom settings
./scripts/launch_tpch_cluster.sh num_workers=3 tpch_file_path=/path/to/tpch/data log_file_path=./logsOnce the cluster is running, use the Python ArrowFlightSQL client to execute queries:
# In a separate terminal, launch the query client
./scripts/launch_python_arrowflightsql_client.sh
# Or with custom query path
./scripts/launch_python_arrowflightsql_client.sh query_path=./tpch/queries/The client script automatically sets up a Python virtual environment and installs required packages:
adbc_driver_manager- Arrow Database Connectivity driver manageradbc_driver_flightsql- ArrowFlightSQL driver for ADBCduckdb- For result display and formattingpyarrow- Arrow Python bindings
Below are a few common commands for executing your queries:
list_queries: list all queries in./tpch/queries/show_query('q1'): show content ofq1run_query('q1'): executeq1explain_query('q1'): show explain ofq1my_query = "SELECT * FROM nation LIMIT 5": assign a custom queryrun_sql(my_query): run a custom queryrun_sql("SELECT * FROM nation LIMIT 5"): run a custom queryexplain_sql(my_query): explain a custom queryexit(): quit the client
To manually set up a distributed cluster, start workers first, then the proxy:
Step 1: Start Workers
In separate terminal windows, start two workers:
# Terminal 1 - Start first worker
DATAFUSION_RAY_LOG_LEVEL=trace ./target/release/distributed-datafusion --mode worker --port 20201
# Terminal 2 - Start second worker
DATAFUSION_RAY_LOG_LEVEL=trace ./target/release/distributed-datafusion --mode worker --port 20202Step 2: Start Proxy
In another terminal, start the proxy connecting to both workers:
# Terminal 3 - Start proxy connected to workers
DATAFUSION_RAY_LOG_LEVEL=trace DFRAY_WORKER_ADDRESSES=worker1/localhost:20201,worker2/localhost:20202 ./target/release/distributed-datafusion --mode proxy --port 20200To make your cluster aware of specific table schemas, you’ll need to define a new environment variable, DFRAY_TABLES, when starting each worker and proxy. This variable should specify tables whose data is stored in Parquet files.For example, the following setup registers two tables—customer and nation—along with their corresponding data sources.
DFRAY_TABLES=customer:parquet:/tmp/tpch_s1/customer.parquet,nation:parquet:/tmp/tpch_s1/nation.parquet DATAFUSION_RAY_LOG_LEVEL=trace ./target/release/distributed-datafusion --mode worker --port 20201
DFRAY_TABLES=customer:parquet:/tmp/tpch_s1/customer.parquet,nation:parquet:/tmp/tpch_s1/nation.parquet DATAFUSION_RAY_LOG_LEVEL=trace ./target/release/distributed-datafusion --mode worker --port 20202
DFRAY_TABLES=customer:parquet:/tmp/tpch_s1/customer.parquet,nation:parquet:/tmp/tpch_s1/nation.parquet DATAFUSION_RAY_LOG_LEVEL=trace DFRAY_WORKER_ADDRESSES=worker1/localhost:20201,worker2/localhost:20202 ./target/release/distributed-datafusion --mode proxy --port 20200Using Views:
To pre-create views that queries can reference (such as for TPC-H q15), you can use the DFRAY_VIEWS environment variable:
# Example: Create a view for TPC-H q15 revenue calculation
DFRAY_VIEWS="CREATE VIEW revenue0 (supplier_no, total_revenue) AS SELECT l_suppkey, sum(l_extendedprice * (1 - l_discount)) FROM lineitem WHERE l_shipdate >= date '1996-08-01' AND l_shipdate < date '1996-08-01' + interval '3' month GROUP BY l_suppkey"
# Use both tables and views in your cluster
DFRAY_TABLES=customer:parquet:/tmp/tpch_s1/customer.parquet,lineitem:parquet:/tmp/tpch_s1/lineitem.parquet,supplier:parquet:/tmp/tpch_s1/supplier.parquet DFRAY_VIEWS="$DFRAY_VIEWS" DATAFUSION_RAY_LOG_LEVEL=trace ./target/release/distributed-datafusion --mode worker --port 20201You can now connect a client to the proxy at localhost:20200 to execute queries across the distributed cluster.
# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install required packages
pip install adbc_driver_manager adbc_driver_flightsql duckdb pyarrow
# Start Python and connect to the cluster
python3import adbc_driver_flightsql.dbapi as dbapi
import duckdb
# Connect to the distributed cluster
conn = dbapi.connect("grpc://localhost:20200")
cur = conn.cursor()
# Execute a simple query
cur.execute("SELECT 1")
result = cur.fetch_arrow_table()
print(result)
# Execute a query with results displayed via DuckDB
cur.execute("SELECT * FROM nation LIMIT 5")
reader = cur.fetch_record_batch()
duckdb.sql("SELECT * FROM reader").show()For development or testing, you can run individual components:
# Single worker (no distributed queries)
./target/release/distributed-datafusion --mode worker --port 20201
# Proxy without workers (limited functionality)
./target/release/distributed-datafusion --mode proxy --port 20200View Available Options
./target/release/distributed-datafusion --helpThe system supports various configuration options through environment variables:
DATAFUSION_RAY_LOG_LEVEL: Set logging level (default: WARN)DFRAY_TABLES: Comma-separated list of tables in formatname:format:pathDFRAY_VIEWS: Semicolon-separated list of CREATE VIEW SQL statements
src/: Main source codeproxy_service.rs: Proxy service for query distributionprocessor_service.rs: Worker node processing logicplanning.rs: Query planning and stage creationflight.rs: Arrow Flight service implementationcodec.rs: Serialization/deserialization for distributed executionk8s.rs: Kubernetes integration
scripts/: Utility scriptslaunch_tpch_cluster.sh: Launch distributed TPC-H benchmark clusterlaunch_python_arrowflightsql_client.sh: Launch Python query clientbuild_and_push_docker.sh: Docker build and push scriptpython_tests.sh: Python test runner
tests/: Integration teststpch_validation.rs: TPC-H validation integration testscommon/mod.rs: Shared test utilities and helper functions
tpch/queries/: TPC-H benchmark SQL queriestestdata/: Test data filesk8s/: Kubernetes deployment files
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
This project was originally developed at DataDog and has been donated to the open source community.