Aerospike Graph Service (AGS)
An Apache TinkerPop-compatible graph database engine backed by Aerospike. Designed for low-latency graph traversals at scale: terabytes of vertices and edges, thousands of concurrent queries, single-digit-millisecond p99, while keeping a plain, Gremlin-standard interface on the wire.
Documentation: User guides and deployment procedures at aerospike.com/docs/graph.
What is Aerospike Graph Service
Aerospike Graph Service (AGS) is a JVM process that speaks the standard
TinkerPop Gremlin wire protocol over WebSocket and stores its data in
an Aerospike cluster. Use any Gremlin driver variant
(gremlin-python, gremlin-javascript, tinkerpop-client in Java,
and other TinkerPop-compatible drivers), issue normal Gremlin traversals and the
service translates them into efficient Aerospike operations, applies
query-planning optimizations specific to Aerospike's data model, and
streams results back to the driver.
Why another graph database?
- Aerospike as the storage tier. Inherit Aerospike's strong consistency, predictable sub-millisecond reads, horizontal scale, hybrid-memory architecture, and cross-datacenter replication. Graph state is another flavor of workload on top of a high-performance, battle-tested key-value store.
- Standard Gremlin on the wire. Anything that speaks TinkerPop 3.7.x works. No bespoke query language, no custom drivers. TinkerPop 3.8 is not supported because of breaking changes in that line.
- Aerospike-native data layout. Vertices and edges are stored in
a
packedon-disk layout tuned for Aerospike's record structure, keeping adjacency information co-resident with the vertex so that most traversal hops resolve in a single Aerospike read. Seedocs/DATA_MODEL_DESIGN.md. - Scale-out OLAP. The Spark-backed OLAP module lets you run
GraphComputerjobs (for example PageRank, connected components, custom VertexPrograms) over the full graph without holding it in a single JVM. - Bulk loading. A Spark-backed bulk loader ingests CSV / GraphML / GraphSON vertex and edge files directly into the Aerospike data model, bypassing the query path for order-of-magnitude faster initial loads.
Quickstart
┌──────────────┐ Gremlin (ws://host:8182) ┌─────────────────────┐ Aerospike ┌─────────────────┐
│ Your app │ ───────────────────────────> │ Graph Service │ ───────────> │ Aerospike │
│ (any lang) │ <─────────────────────────── │ (this container) │ <─────────── │ cluster │
└──────────────┘ └─────────────────────┘ └─────────────────┘Quickstart with Docker Compose
If you do not already have an Aerospike cluster, graph-service-examples/
ships a docker-compose.yaml that starts AGS, Aerospike Database, and Zipkin in one command:
cd graph-service-examples
docker compose up -dgraph-service-examples/ also includes runnable example
applications and sample datasets, plus a bulk-load guide. The
official step-by-step walkthrough is at
aerospike.com/docs/graph/quick-start.
The rest of this section shows how to run AGS in Docker. Pick one path below. See Deploy Aerospike Graph Service with Docker for the full deployment guide.
Prerequisites
Before you run AGS in Docker, you need:
- An Aerospike Database deployment compatible with this release. AGS works with Community Edition; if you choose Enterprise or Standard Edition, provide the feature key required by that database edition.
- An Aerospike Database version compatible with this release. See
docs/COMPATIBILITY.md. - A namespace that already exists on the cluster with
default-ttlset to0. See TTL on the Aerospike namespace below. - If access control is enabled on Aerospike, the AGS database user needs
sys-adminandread-writeprivileges.
Aerospike Database in Docker
Use this path if you do not already have Aerospike running. It starts Aerospike Database and AGS together on a shared Docker network. Do not also run Run AGS with Docker afterward.
- Pull the images:
docker pull aerospike/aerospike-server-enterprise:latest
docker pull aerospike/aerospike-graph-service:latest- Start Aerospike Database and AGS:
docker network create ags-net 2>/dev/null || true && \
docker rm -f aerospike graph 2>/dev/null || true && \
docker run -d --name aerospike --network ags-net \
aerospike/aerospike-server-enterprise:latest && \
until docker exec aerospike asinfo -v 'status' 2>/dev/null | grep -q ok; do sleep 1; done && \
docker run -d --name graph --network ags-net --restart unless-stopped \
-p 8182:8182 \
-e aerospike.client.namespace="test" \
-e aerospike.client.host="aerospike:3000" \
aerospike/aerospike-graph-service:latestaerospike:3000 is the Aerospike container name on ags-net plus the default service
port. test is the default namespace in the Aerospike Docker image. Change these only
if you configured Aerospike differently. This example uses the Enterprise image;
you can use Community Edition instead when your deployment does not need an
Enterprise-only database capability.
Run AGS with Docker
Use this path only when Aerospike is already running somewhere else (on the host, on another machine, or in a container you started separately). Skip this section if you used Aerospike Database in Docker above.
- Pull the AGS Docker image:
docker pull aerospike/aerospike-graph-service:latest- Run the AGS container:
docker run -d --name graph \
-p 8182:8182 \
-e aerospike.client.namespace="NAMESPACE" \
-e aerospike.client.host="HOSTNAME:PORT" \
aerospike/aerospike-graph-service:latestHOSTNAME:PORT: hostname or IP of an Aerospike seed node and its service port. The default Aerospike service port is3000. Examples:db.example.com:3000for a remote cluster, orhost.docker.internal:3000when Aerospike runs on the host outside Docker. Do not uselocalhosthere. Inside the AGS container,localhostrefers to the AGS container itself, not your machine.NAMESPACE: name of an existing namespace on that cluster, for exampletest. List namespaces withasadm(show namespaces).
If Aerospike is running in a Docker container, put AGS on the same Docker network and
use the Aerospike container name as HOSTNAME (for example aerospike:3000), or get
its IP address with:
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' AEROSPIKE_CONTAINER_IDReplace AEROSPIKE_CONTAINER_ID with the Aerospike container ID or name.
Server output
AGS logs to stdout. When the container is started with -d, follow the logs with:
docker logs -f graphAfter startup completes, the log includes:
Channel started at port 8182.TTL on the Aerospike namespace
If AGS fails to start with a default-ttl error, set the namespace TTL to 0:
- Start the Aerospike Tools container:
docker run -it aerospike/aerospike-tools asadm -h HOSTNAMEReplace HOSTNAME with the hostname or IP of your Aerospike server. If Aerospike is
running on a Docker network (for example ags-net from Aerospike Database in Docker):
docker run -it --network ags-net aerospike/aerospike-tools asadm -h aerospike- At the
Admin>prompt, enable dynamic configuration:
enable- Set
default-ttlto0:
manage config namespace NAMESPACE param default-ttl to 0- Restart AGS:
docker start graphConnect with a Gremlin driver
With AGS running and port 8182 published (as in the steps above), connect to it from
your application using any TinkerPop 3.7.x driver. Use exactly 3.7.x. A 3.8.x driver
will fail with a Could not locate method error.
Python
- Install the driver:
pip install 'gremlinpython>=3.7,<3.8'- Connect to AGS and run a traversal:
from gremlin_python.process.anonymous_traversal import traversal
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
g = traversal().with_remote(
DriverRemoteConnection("ws://localhost:8182/gremlin", "g")
)
# Write two vertices and an edge
alice = g.addV("person").property("name", "alice").next()
bob = g.addV("person").property("name", "bob").next()
g.add_e("knows").from_(alice).to(bob).property("since", 2020).iterate()
# Read them back
friends = g.V().has("person", "name", "alice").out("knows").values("name").to_list()
print(friends) # ['bob']Java
- Create a Maven project if you do not have one, then add the driver to your
pom.xml:
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-driver</artifactId>
<version>3.7.3</version>
</dependency>- Connect to AGS and run a traversal (imports omitted for brevity):
Cluster cluster = Cluster.build("localhost").port(8182).create();
GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster, "g"));
List<Object> friends = g.V().has("person", "name", "alice")
.out("knows").values("name").toList();Any other TinkerPop-compatible driver works the same way. A more complete walk-through,
including loading sample datasets, is in docs/SETUP.md.
For more runnable end-to-end examples, notebooks, sample datasets, bulk-load
recipes, and application patterns see graph-service-examples/.
Configuration
The Docker run commands above pass configuration as -e environment variables. For
deployments with more settings, you can instead write a properties file and mount it
into the container. Both approaches use the same property names.
A minimal aerospike-graph.properties:
aerospike.client.host=HOSTNAME:PORT
aerospike.client.namespace=NAMESPACEMount it with the -v flag instead of the -e flags:
docker run -d --name graph \
-p 8182:8182 \
-v $PWD/aerospike-graph.properties:/opt/aerospike-graph/aerospike-graph.properties \
aerospike/aerospike-graph-service:latestThe mount path inside the container must be
/opt/aerospike-graph/aerospike-graph.properties. The local path ($PWD/...) can be
anywhere on your machine.
For the full list of available properties (auth, TLS, caching, indexing, metrics, and
JVM heap sizing), see docs/CONFIG_OPTIONS.md and the
Configuration reference on
aerospike.com.
Documentation
Core docs, organized roughly by audience:
User guides
docs/SETUP.md: minimal properties and connection (runtime-focused, not a contributor build guide)docs/DOCKER_USER_DOCUMENTATION.md: Docker-specific deployment patternsdocs/CONFIG_OPTIONS.md: complete configuration reference for this repositorydocs/INDEX_USAGE.md: when and how to use indexesdocs/METRICS.md: operational metrics and what to alert ongraph-service-examples/: runnable example applications, notebooks, and sample datasets
Design docs
docs/DATA_MODEL_DESIGN.md: the details about thepackeddata modeldocs/INDEX_DESIGN.md: how graph leverages Aerospike secondary indexesdocs/ID_MANAGEMENT.md: vertex/edge ID generation and allocationdocs/BULK_LOADER_DESIGN.md: architecture of the Spark bulk loaderdocs/GRAPH_OLAP.md: Spark-backed GraphComputer (OLAP) guidancedocs/CACHE_MANAGEMENT.md: multi-level cache hierarchydocs/WRITE_CONSISTENCY.md: edge and vertex write consistency
Operations
docs/GRAPH_MAX_MEMORY.md: heap sizing guidancedocs/TTL.md: time to live (TTL) semanticsdocs/QUERY_TRACING.md: per-query tracingdocs/SUPERNODE_FLAG.md: handling extreme-degree vertices
For install, deploy, query, and manage guides, see aerospike.com/docs/graph.
Building from source
Codename
firefly. The internal codename remains in Java packages (com.aerospike.firefly.*) and the root MavenartifactId. The shipped product is Aerospike Graph Service; runtime configuration usesaerospike.*keys. For more background, see Whyfireflypersists in identifiers in CONTRIBUTING.md.
The repository is laid out as a multi-module Maven build:
| Module | What's in it |
|---|---|
aerospike-graph-gremlin/ | Core OLTP engine. FireflyGraph, the packed storage layout, indexes, traversal strategies, and the embedded gremlin-server. |
aerospike-graph-bulk-loader/ | Spark-based bulk loader for CSV inputs. |
aerospike-graph-olap/ | Spark-backed GraphComputer (OLAP) implementation for cluster-wide analytics. |
aerospike-graph-api/ | Stable API surface shared between the engine and extensions. |
Deeper design docs live under docs/. See the Documentation section.
Prerequisites
- JDK 17 for the primary CI and development path. Maven compiles Java 11 bytecode; see
docs/COMPATIBILITY.mdfor the current evidence-based matrix. - Maven 3.9+ (matches CI). See
docs/COMPATIBILITY.md. - Docker with Buildx for building container images.
- Python 3 and
python_on_whalesforscripts/build-docker.py(pip install python_on_whales). - An Aerospike Database cluster compatible with this release. See
docs/COMPATIBILITY.md. - CI-style cluster:
scripts/start_aerospike.shstarts a multi-node Enterprise cluster and requires either.github/aerospike/features.conforAEROSPIKE_FEATURES_B64. That path is oriented toward matching CI, not general laptop setup. On macOS,scripts/macos-start-aerospike.shruns the same flow inside a container with the Docker socket mounted. It assumes a local image tag such asfirefly:devalready exists.
Maven compiles with Java 11. The Dockerfiles in docker/ package a JDK 17 runtime.
Build the JARs
mvn -ntp -DskipTests clean packageShaded runnable JARs are written under each module's target/ directory. VERSION matches the <version> in the root pom.xml, for example:
aerospike-graph-gremlin/target/aerospike-graph-gremlin-VERSION.jaraerospike-graph-bulk-loader/target/aerospike-graph-bulk-loader-VERSION.jaraerospike-graph-olap/target/aerospike-graph-olap-VERSION.jar(when built)
Run from the JVM
From the repository root, after building the gremlin module:
mvn -ntp -DskipTests -pl aerospike-graph-gremlin -am package
java -jar aerospike-graph-gremlin/target/aerospike-graph-gremlin-*.jar conf/local.yamlconf/local.yaml points Gremlin Server at the sample properties under conf/. Edit conf/aerospike-graph.properties (or the YAML) so aerospike.client.host reaches your Aerospike seeds.
Verify the process is listening: in the server log output, look for
Channel started at port 8182. (the same line as in the Docker quickstart).
Build the Docker image
Do not run docker build from the repository root without the build arguments the docker/Dockerfile expects. Use the helper script from the repository root:
pip install python_on_whales
python3 scripts/build-docker.py --tags firefly:dev --platforms linux/amd64--slim: builds only the graph JAR and usesdocker/Dockerfile-slim. The image has no bulk loader (smaller footprint, same idea asaerospike/aerospike-graph-service:latest-slimon Docker Hub).--use_local: skip Maven and reuse JARs already present under*/target/.
Run the image you built. Replace HOSTNAME:PORT and NAMESPACE as in Run AGS with Docker:
docker run -d -p 8182:8182 \
-e aerospike.client.host=HOSTNAME:PORT \
-e aerospike.client.namespace=NAMESPACE \
firefly:devReleased user-facing images are published on Docker Hub as
aerospike/aerospike-graph-service:VERSION (with a moving :latest
tag). The standard image includes the standalone bulk loader. The slim image is graph-only.
License-clean dependency graph
mvn -ntp -Plicense-check verifyThis profile is opt-in; the dedicated license workflow runs it when relevant files change and fails the build
if any compile/runtime dependency's license is not on the Apache-2.0
-compatible allowlist in the root pom.xml. The enforcement report is
written to target/THIRD_PARTY.enforce.txt. A separate inventory at
THIRD_PARTY.txt is generated during a default verify run.
Testing
The default mvn test run is self-contained for unit tests (no live Aerospike required for the default Surefire selection):
mvn -ntp testTests that need a real Aerospike cluster, Docker, or other heavy fixtures are excluded or gated in the root POM Surefire configuration and in CI. The full matrix runs in .github/workflows/ with the cluster helpers under .github/aerospike/.
Benchmark tests use JMH.
They live under aerospike-graph-gremlin/src/test/java/.../benchmark/ and are
skipped by default. Run them with:
mvn -ntp -pl aerospike-graph-gremlin test -Dtest='BenchmarkTest*'Contributing
We welcome pull requests. Before you start:
- Read
CONTRIBUTING.mdfor the development workflow and DCO sign-off requirement. - Check the issue tracker for open discussions on the area you want to work in. For anything non-trivial, open an issue first so we can agree on the approach.
- Follow the Code of Conduct in all project spaces.
For security-sensitive reports, follow the private disclosure process
in SECURITY.md instead of opening a public issue.
License
Aerospike Graph Service is licensed under the Apache License,
Version 2.0. Copyright notices and third-party attributions
are in NOTICE. The machine-generated dependency inventory
is in THIRD_PARTY.txt (from a default verify run) and
target/THIRD_PARTY.enforce.txt (from mvn -ntp -Plicense-check verify).
Trademarks
"Aerospike" is a registered trademark of Aerospike, Inc. Use of the mark is governed by the Aerospike trademark policy. The Apache-2.0 license on the source and binaries in this repository does not grant any trademark license.
"Apache", "Apache TinkerPop", "Gremlin", and "Apache Spark" are trademarks of the Apache Software Foundation.
Acknowledgements
This project stands on the shoulders of:
- Apache TinkerPop: the Gremlin language, server, and provider framework.
- Apache Spark: the OLAP and bulk-loader runtimes.
- Netty: the async I/O foundation.
- The Aerospike Java client: the storage layer's transport.
- Every contributor to the many transitive dependencies listed in
NOTICEandTHIRD_PARTY.txt.