Open, SQL-native time-series database for telemetry you need to keep. 34M+ records/sec ingestion, 8M+ rows/sec queries. InfluxDB Line Protocol and Telegraf compatible. Open Parquet on your storage. Single binary. S3/Azure native. Air-gap ready. AGPL-3.0.
翻译准备中
正在加载完整 README。 以下为已保存的摘录。
Open, SQL-native time-series database for telemetry you need to keep. Arc ingests 34M+ records/sec, stores data as standard Parquet on infrastructure you own, and lets you query recent and historical data together. InfluxDB Line Protocol and Telegraf compatible. Single binary. AGPL-3.0.
Prefer a UI? Arc Launchpad is a self-hosted web console for the Arc instances you run — SQL console, schema explorer, logs, monitoring, and management for tokens, retention, alerts, continuous queries, and MQTT ingestion. Deploy it alongside Arc with Docker Compose. Docs.查看完整 README ↗Open, SQL-native time-series database for telemetry you need to keep. Arc ingests 38M+ records/sec, stores data as standard Parquet on infrastructure you own, and lets you query recent and historical data together. InfluxDB Line Protocol and Telegraf compatible. Single binary. AGPL-3.0.
Prefer a UI? Arc Launchpad is a self-hosted web console for the Arc instances you run — SQL console, schema explorer, logs, monitoring, and management for tokens, retention, alerts, continuous queries, and MQTT ingestion. Deploy it alongside Arc with Docker Compose. Docs.
Prefer a terminal? arcli is the Arc command line — named connections, SQL queries with table, JSON, CSV or Arrow output, line-protocol and MessagePack writes, bulk imports, and admin for tokens, retention, continuous queries, backups and compaction.
brew install basekick-labs/tap/arcli, or deb, rpm, Arch and Docker. Docs.
Machines, services, vehicles, and devices produce data continuously. The operational problem is not only ingesting the latest readings — it is keeping the full-resolution history available for debugging, analysis, compliance, and the next question nobody has asked yet.
Teams evaluating a time-series database usually run into the same trade-offs:
Arc is built for teams that want to keep the data, query the whole history, and start with a small deployment. It combines high-throughput ingestion, automatic Parquet storage and compaction, analytical SQL, retention policies, and continuous queries in one binary.
Built for aerospace telemetry. Useful anywhere machines never stop producing data.
Arc is a complete time-series analytical database: ingestion pipeline, Parquet storage engine, compaction system, SQL query layer, retention policy manager, continuous query scheduler, and telemetry integrations — in one binary. It uses DuckDB as its query engine, while Arc adds the pieces needed to run a durable ingestion and analytics service: high-throughput writes with automatic Parquet flushing, background compaction, scheduled compute, data lifecycle management, authentication, backup and restore, and enterprise clustering.
Arc is not a wrapper. You don't bring your own ingestion, compaction, or retention policies. Arc provides the full stack.
-- Telemetry: hourly sensor summary across a full history
SELECT
device_id,
DATE_TRUNC('hour', timestamp) AS hour,
AVG(value) AS average_value,
MIN(value) AS minimum_value,
MAX(value) AS maximum_value
FROM telemetry.sensor_readings
WHERE timestamp > NOW() - INTERVAL '30 days'
GROUP BY device_id, hour
ORDER BY hour DESC;
-- Telemetry: correlate readings with device metadata
SELECT
d.site,
r.device_id,
AVG(r.value) AS average_value
FROM telemetry.sensor_readings AS r
JOIN telemetry.devices AS d ON d.device_id = r.device_id
WHERE r.timestamp > NOW() - INTERVAL '24 hours'
GROUP BY d.site, r.device_id;
Standard SQL. Window functions, CTEs, joins, aggregations. No proprietary query language.
Arc accepts InfluxDB Line Protocol directly, so existing Telegraf inputs can write to Arc without changing the collection layer. A low-risk migration usually looks like this:
See the InfluxDB migration guide, or compare Arc with TimescaleDB, InfluxDB, ClickHouse, and Elasticsearch.
See Arc in action: https://basekick.net/demos
Benchmarked on Apple MacBook Pro M3 Max (14 cores, 36GB RAM, 1TB NVMe). Test config: 12 concurrent workers, 1000-record batches, columnar data.
| Protocol | Throughput | p50 Latency | p99 Latency |
|---|---|---|---|
| MessagePack Columnar | 38.1M rec/s | 0.26ms | 1.19ms |
| MessagePack + Zstd | 30.3M rec/s | 0.35ms | 1.23ms |
| MessagePack + GZIP | 26.4M rec/s | 0.39ms | 1.36ms |
| Line Protocol | 9.3M rec/s | 1.07ms | 3.38Ms |
All rows measured over a 60-second sustained run. The MessagePack Columnar row is 2,288,281,000 records ingested in 60 seconds — and that's not rows streamed into a memory buffer: every record was received over HTTP, decoded, time-sorted, and durably written to disk as queryable Parquet, at 0.26ms median latency, on a laptop.
These numbers ship in 27.01.1. Since 26.09.1 (34.0M, 24.9M, 24.6M and 4.7M rec/s): line-protocol writes parse straight into typed columns (#1299), and flushes copy each column once less on the way to Parquet.
26.09.1 stopped dictionary-encoding Parquet at ingest (compaction re-encodes files anyway) and made the msgpack columnar path decode payloads directly into typed column arrays, eliminating per-value allocations — see the 26.09.1 release notes.
Automatic background compaction merges small Parquet files into optimized larger files:
| Metric | Before | After | Reduction |
|---|---|---|---|
| Files | 43 | 1 | 97.7% |
| Size | 372 MB | 36 MB | 90.4% |
Benefits:
Arc speaks three wire formats from the same query engine. Arrow IPC is the throughput leader for analytical clients (Grafana, pyarrow, polars) that can take an Arrow dependency — zero-copy from the engine's internal columnar buffers. MessagePack (columnar, stable as of 26.09.1) is the choice for clients that don't speak Arrow but want smaller bytes and faster decode than JSON — same envelope shape as JSON, native binary types for timestamps and binary columns. JSON stays the default for ergonomic compatibility.
Benchmark: Arc 27.01.1 (main at b4d98a31, October 2026), M3 Max, query_suite from arc-benchmarks, 5 iterations per query, latency is p50 in milliseconds. One session, one dataset: a 532.6M-row cpu measurement (60 s of sustained_bench msgpack ingest spread over 24 hours, hourly-compacted: 25 hour partitions, 100 files), so the three columns are apples-to-apples.
| Query | JSON (ms) | MessagePack (ms) | Arrow IPC (ms) | msgpack vs JSON | Arrow vs JSON |
|---|---|---|---|---|---|
| COUNT(*) — 532.6M rows | 52.9 | 52.1 | 52.5 | 1.02x | 1.01x |
| SELECT LIMIT 10K | 12.3 | 12.5 | 11.9 | 0.99x | 1.04x |
| SELECT LIMIT 100K | 18.9 | 17.4 | 14.9 | 1.09x | 1.27x |
| SELECT LIMIT 500K | 43.9 | 38.9 | 27.5 | 1.13x | 1.60x |
| SELECT LIMIT 1M | 71.6 | 65.4 | 39.6 | 1.09x | 1.81x |
| Time Range (1h) LIMIT 10K — no rows in window¹ | 2.6 | 2.7 | 3.1 | 0.96x | 0.84x |
| Time Range (7d) LIMIT 10K | 13.6 | 13.5 | 12.9 | 1.01x | 1.05x |
| Time Bucket (1h, 7d) | 605 | 606 | 612 | 1.00x | 0.99x |
| Date Trunc (day, 30d) | 605 | 609 | 608 | 0.99x | 1.00x |
| GROUP BY host | 502 | 501 | 500 | 1.00x | 1.00x |
Best throughput on LIMIT 1M (1M-row payload, single connection):
¹ The newest data is two hours old, so the window is empty. Arc 27.01.1 answers it from the newest partition alone (it filters to zero rows) instead of reading the whole measurement, as before (49 ms); measured on main at 2eecb2d1.
Notes on the table: the wire-format differences show on response-heavy queries (≥100k rows) where encoding dominates the per-request wall time. For aggregations (Time Bucket, Date Trunc, GROUP BY) the response is a few rows and DuckDB execution is nearly all of the wall time; all three formats converge. Arrow IPC copies the engine's column buffers. Since 27.01.1 every format streams straight to the socket, and JSON and MessagePack are encoded on several cores (JSON by batch, MessagePack by column run, handed to encoder goroutines and written in order); MessagePack's typed columnar encoder keeps it ahead of JSON on large results.
The MessagePack endpoint is stable as of 26.09.1: its response shape and type vocabulary are a published contract pinned by a golden test, so clients can bind to them. It's the best general-purpose format for a client not using Arrow directly — columnar, typed, and it accepts SHOW statements, which the Arrow endpoint doesn't. See the 26.09.1 release notes for the wire-format contract.
Arc deploys as one self-contained executable: DuckDB and its dependencies are linked in, and on Linux it needs only the system C library (glibc 2.34 or newer) and libgcc_s, which every distro ships. No JVM, no Python environment, no PostgreSQL cluster to manage, no ZooKeeper ensemble to babysit. Run it on a laptop, a factory edge box, an on-premises server, or a Kubernetes cluster. Same binary, same config surface.
# Build
make build
# Run
./arc
# Verify
curl http://localhost:8000/health
# Docker Hub
docker run -d \
-p 8000:8000 \
-v arc-data:/app/data \
basekicklabs/arc:latest
# or GitHub Container Registry
docker run -d \
-p 8000:8000 \
-v arc-data:/app/data \
ghcr.io/basekick-labs/arc:latest
Multi-arch images (linux/amd64 + linux/arm64) are published to both registries on every release.
brew install basekick-labs/tap/arc
Apple Silicon. DuckDB is statically linked, so there are no runtime dependencies. (Use brew install --formula arc if you tap first, to disambiguate from the arc browser cask.)
Linux packages run on glibc 2.34 or newer: Ubuntu 22.04+, Debian 12+, RHEL/Rocky/Alma 9+, Amazon Linux 2023, Fedora 35+. Ubuntu 20.04 and RHEL 8 are not supported.
wget https://github.com/basekick-labs/arc/releases/download/v26.09.3/arc_26.09.3_amd64.deb
sudo dpkg -i arc_26.09.3_amd64.deb
sudo systemctl enable arc && sudo systemctl start arc
wget https://github.com/basekick-labs/arc/releases/download/v26.09.3/arc-26.09.3-1.x86_64.rpm
sudo rpm -i arc-26.09.3-1.x86_64.rpm
sudo systemctl enable arc && sudo systemctl start arc
Works on Arch Linux and Arch-based distros such as Omarchy (x86_64 and aarch64).
wget https://github.com/basekick-labs/arc/releases/download/v26.09.3/arc-26.09.3-1-x86_64.pkg.tar.zst
sudo pacman -U arc-26.09.3-1-x86_64.pkg.tar.zst
sudo systemctl enable arc && sudo systemctl start arc
helm install arc https://github.com/basekick-labs/arc/releases/download/v26.09.3/arc-26.09.3.tgz
# Prerequisites: Go 1.26+
# Clone and build
git clone https://github.com/basekick-labs/arc.git
cd arc
make build
# Or build directly with Go (the duckdb_arrow tag is required)
go build -tags=duckdb_arrow ./cmd/arc
# Run
./arc
For US defense/federal and other regulated environments, Arc ships an optional
arc-fips build: the same source at the same version, compiled against the
CMVP-certified Go Cryptographic Module and run in FIPS-only mode. Pick the
-fips artifact instead of the standard one.
# Binary — download arc-fips-linux-amd64 (or -arm64) from the release
# Container — same repos, -fips tag suffix:
docker run -d -p 8000:8000 -v arc-data:/app/data ghcr.io/basekick-labs/arc:VERSION-fips
# or basekicklabs/arc:VERSION-fips
# Build from source:
make build-fips # -> arc-fips (GOFIPS140=v1.0.0, -tags=duckdb_arrow,fips)
The FIPS build reports the same version as the standard build and logs
"fips_mode":true at startup. Cutover note: existing bcrypt-hashed API
tokens must be rotated when moving to the FIPS build (it stores new tokens with
PBKDF2 and fails bcrypt verification closed). The Go Cryptographic Module is
CMVP-certified; Arc itself is not a CMVP-listed module. See the
FIPS 140-3 mode guide.
| Tool | Description | Link |
|---|---|---|
| Arc Launchpad | Self-hosted web UI: SQL console, schema explorer, logs, monitoring, and management for tokens, retention, alerts, continuous queries, MQTT ingestion, and teams | GitHub · Docs |
| arcli | Command-line client: connection profiles, SQL queries (table, JSON, CSV, Arrow), writes and bulk imports, and admin for tokens, retention, continuous queries, backups, compaction and logs. Homebrew, deb/rpm/Arch, Docker | GitHub · Docs |
| VS Code Extension | Browse databases, run queries, visualize results | Marketplace |
| Grafana Data Source | Native Grafana plugin for dashboards and alerting | GitHub |
| Telegraf Output Plugin | Ship data from 300+ Telegraf inputs directly to Arc | Docs |
| Python SDK | Query and ingest from Python applications | PyPI |
| Superset Dialect (JSON) | Apache Superset connector using JSON transport | GitHub |
| Superset Dialect (Arrow) | Apache Superset connector using Arrow transport |
Columnar storage: Parquet format with full analytical SQL engine
Workloads: Industrial IoT, manufacturing, energy, fleet telemetry, aerospace, observability, and event analytics
Ingestion: MessagePack columnar (fastest), InfluxDB Line Protocol, MQTT, TLE (satellite telemetry)
Query: Full analytical SQL; JSON, columnar MessagePack, and Apache Arrow IPC responses
Compaction: Tiered (hourly/daily) automatic Parquet file merging — 10x storage reduction; see hourly compaction tuning
Data Lifecycle: Retention policies, continuous queries, tiered storage (hot/cold)
Durability: Optional write-ahead log (WAL), backup and restore; WAL recovery monitoring
Storage: Local filesystem, S3 and S3-compatible object stores (SeaweedFS, R2, MinIO, ...), Azure Blob
Auth: Token-based authentication with in-memory caching
Data Management: GDPR-compliant delete operations
Observability: Prometheus metrics, structured logging, graceful shutdown
Reliability: Circuit breakers, retry with exponential backoff
Supply chain: SBOM (SPDX + CycloneDX), Trivy scans, cosign-signed releases, SLSA L3 provenance
FIPS 140-3: Optional arc-fips build against the CMVP-certified Go Cryptographic Module — see Installation
Edge Sync (new in 26.09.1): Spoke-to-hub data transport for disconnected operations, over the network or via signed air-gap bundles. Network spokes retain the manual trigger; a valid paid license also schedules sync. Configure edge_sync.spoke.sync_interval (default 5m) and edge_sync.spoke.sync_retry_interval (default ) to set the success and retry cadence.
Arc uses TOML configuration with environment variable overrides.
[server]
host = "0.0.0.0"
port = 8000
[storage]
backend = "local" # local, s3, minio
local_path = "./data/arc"
[ingest]
max_buffer_age_ms = 5000 # flush a buffer at most this old
max_buffer_size = 50000
[auth]
enabled = true
Environment variables use ARC_ prefix:
export ARC_SERVER_PORT=8000
export ARC_STORAGE_BACKEND=s3
export ARC_AUTH_ENABLED=true
See arc.toml for complete configuration reference.
arc/
├── cmd/arc/ # Application entry point
├── internal/
│ ├── api/ # HTTP handlers (Fiber) — query, write, import, TLE, admin
│ ├── audit/ # Audit logging for API operations
│ ├── auth/ # Token authentication and RBAC
│ ├── backup/ # Backup and restore (data, metadata, config)
│ ├── circuitbreaker/ # Resilience patterns (retry, backoff)
│ ├── cluster/ # Raft consensus, node roles, peer file replication, standby stream
│ ├── compaction/ # Tiered hourly/daily Parquet file merging
│ ├── config/ # TOML configuration with env var overrides
│ ├── database/ # Query engine and connection management
│ ├── governance/ # Per-token query quotas and rate limiting
│ ├── ingest/ # MessagePack, Line Protocol, TLE, Arrow writer
│ ├── license/ # License validation and feature gating
│ ├── logger/ # Structured logging (zerolog)
│ ├── metrics/ # Prometheus metrics
│ ├── mqtt/ # MQTT subscriber — topic-to-measurement ingestion
│ ├── pruning/ # Query-time partition pruning
│ ├── queryregistry/ # Active/completed query tracking
│ ├── scheduler/ # Continuous queries and retention policies
│ ├── shutdown/ # Graceful shutdown coordinator
│ ├── sql/ # SQL parsing utilities
│ ├── storage/ # Local, S3, Azure backends
│ ├── telemetry/ # Usage telemetry
│ ├── tiering/ # Hot/cold storage lifecycle management
│ └── wal/ # Write-ahead log
├── pkg/models/ # Shared data structures (Record, ColumnarRecord)
├── benchmarks/ # Performance benchmarking suites
├── deploy/ # Docker Compose and Kubernetes configs
├── helm/ # Helm charts
├── scripts/ # Utility scripts (analysis, backfill, debugging)
├── arc.toml # Configuration file
├── Makefile # Build commands
└── go.mod
make deps # Install dependencies
make build # Build binary
make run # Run without building
make test # Run tests
make test-coverage # Run tests with coverage
make bench # Run benchmarks
make lint # Run linter
make fmt # Format code
make clean # Clean build artifacts
Arc is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
For commercial licensing, contact: [email protected]
Want to join this list? See CONTRIBUTING.md and the good first issue queue.
Thanks to everyone who has contributed code to Arc:
And a thank-you to community members whose bug reports drove fixes:
| GROUP BY host + hour | 835 | 836 | 836 | 1.00x | 1.00x |
| GitHub |
30s.part as a present file (#965), ListStaged reports only partials its own DeleteStaged accepts so abandoned-partial reclaim stops warning on legacy illegal keys (#906)default (#1055); the tiering files endpoint rejects a negative limit instead of panicking on a negative slice bound (#1051)arc_ingest_flush_deferred_total reporting what used to be a silent drop (#966); continuous-query create and update apply Arc's database-name rule, and update reports an omitted database separately from an invalid one (#995); compaction's de-duplication row count read from the Parquet file metadata that actually carries it, so the dedup-ratio log fires for the first time (#1019); a panic in the experimental arcx Arrow IPC stream writer now marks the response incomplete with an invalid-IPC marker and an Arc-Stream-Truncated trailer, instead of ending at a batch boundary that clients read as complete (#904); experimental arcx Arrow IPC queries are registered before the engine is chosen, so they carry an X-Arc-Query-ID, appear in active-query tracking and history, propagate registry cancellation, and dispose of their entry on success, failure, timeout or a recovered panic rather than staying listed as running (#911); WAL recovery replays only entries whose batch had not yet reached Parquet, through a per-entry tracked identity and a checkpoint written after the flush is confirmed — closing the permanent duplicate-row bug for tagless measurements, where compaction can never dedup (#948); same-name token-create conflicts no longer counted or logged as rejected entries at every restart (#973); a delete-API rewrite after a writer failover names the rewriting node as the file's origin (#984); a Raft manifest batch is applied under one lock so readers never see a half-applied compaction (#910); a snapshot restore announces the files it dropped so a rejoined node removes the replicas the cluster deleted while it was away (#983); a replica refreshes a file whose manifest content changes while it is being pulled, with the FSM signalling content changes separately from registrations and a verified copy kept until the successor lands (#907); delete API WHERE validation scans a string-literal-masked clause, so values containing SQL words or punctuation can be deleted again (#937, landed via #1079); the measurement endpoint's where pre-filter matches keywords as whole words on a literal-masked clause, so values and identifiers containing SQL words are accepted again (#988); reclaiming the Iceberg manifest metadata that expired snapshots leave behind — implemented independently in #923, three weeks ahead of the fix that shipped for the same issue (#835); the enterprise crash smokes verify acknowledged records survive WAL replay, rejecting an idle kill target or a crash that never triggered (#1004); each compaction subprocess capped at the lower of the licence core count and the cores Arc may actually use, after the automatic thread default is resolved (#1043); the automatic compaction thread count divided by max(2, compaction.max_concurrent) instead of always halving, so raising concurrency no longer gives every subprocess half the cores - and by dropping the quota test the first draft used, the fix reaches cpuset-limited containers, where NumCPU already shrinks and a quota comparison sees nothing (#1041); local-backend compaction reads each Parquet input from its existing path instead of first copying it into the compaction temp directory, cutting sampled peak temp-directory usage from 1.88 MB to 0.36 MB on a 42-file partition, with the streaming path kept for S3 and Azure and the concurrent-input-deletion behaviour defined and tested (#990)