Skip to content

Distributed data structures and coordination primitives for Kubernetes

Atomix provides the building blocks of distributed cloud applications. Built by distributed systems engineers and designed to make distributed systems simple and accessible to Kubernetes application developers.

Get started Learn more

What does it do?

  • Shared data structures

    Atomix isn't just a simple key-value store. The runtime API supports common data structures that can be used by applications to store and share state. Lists, maps, sets, and purpose-built data structures are provided to enable a variety of use cases.

  • Distributed coordination primitives

    Primitives for solving common distributed systems problems like leader election, distributed locking, scheduling, and more. Atomix distributed coordination primitives enable developers to implement distributed systems solutions without distributed systems expertise.

  • Cross-language compatibility

    The Atomix runtime is built on gRPC, enabling SDKs in a variety of different languages. Applications can be written in your language of choice, and containers or services can share state across languages.

  • Storage abstraction layer

    The Atomix runtime provides a unified API across numerous databases and protocols, decoupling application code from data stores to enable applications to be developed independent of the underlying architecture.

  • Pluggable data stores

    Atomix provides both custom distributed systems protocols and database proxies. Data storage is driven by configuration, so Atomix-enabled applications can choose their own data stores and even swap between data stores without changing a single line of code.

  • Built for Kubernetes

    Atomix is built from the ground up for Kubernetes. Data stores and applications are managed via custom resources, providing seamless integration with Kubernetes tools like kubectl and Helm.

How does it work?

Write your application

Primitives are the building blocks of distributed application in Atomix. Choose from a variety of different data structures to store application state or share state across pod or services. Distributed coordination primitives enable safe interaction with other nodes and services within the Kubernetes cluster. Use the primitives that are right for your use case.

Learn more

// Build the counter
counter, err := atomix.Counter("my-counter").
    Get(context.Background())
if err != nil {
    ...
}

// Increment the counter
count, err = counter.Increment(context.Background())
if err != nil {
    ...
}

// Get the counter value
value, err = counter.Get(context.Background())
if err != nil {
    ...
}
// Build the leader election
election, err := atomix.LeaderElection("my-counter").
    Get(context.Background())
if err != nil {
    ...
}

// Get the current leadership term
term, err := election.GetTerm(context.Background())
if err != nil {
    ...
}

// Enter the election
term, err = election.Enter(context.Background())
if err != nil {
    ...
}
// Get a string list
l, err := atomix.List[string]("my-list").
    Codec(generic.Scalar[string]()).
    Get(context.Background())
if err != nil {
    ...
}

// Append a value to the list
err = l.Append(context.Background(), "Hello world!")
if err != nil {
    ...
}

// Iterate through the items in the list
items, err := l.Items(context.Background())
if err != nil {
    ...
}
for {
    item, err := items.Next()
    if err == io.EOF {
        break
    }
    ...
}
// Build the lock
l, err := atomix.Lock("my-lock").
    Get(context.Background())
if err != nil {
    ...
}

// Acquire the lock
if err := l.Lock(context.Background()); err != nil {
    ...
}

// Do stuff...

// Release the lock
if err := l.Unlock(context.Background()); err != nil {
    ...
}
// Get a string:string map
m, err := atomix.Map[string, string]("my-map").
    Codec(generic.Scalar[string]()).
    Get(context.Background())
if err != nil {
    ...
}

// Write to the map
_, err = m.Put(context.Background(), "foo", "bar")
if err != nil {
    ...
}

// Read from the map
entry, err := m.Get(context.Background(), "foo")
if err != nil {
    ...
}
// Get a string:string multimap
m, err := atomix.MultiMap[string, string]("my-multimap").
    Codec(generic.Scalar[string]()).
    Get(context.Background())
if err != nil {
    ...
}

// Write to the multimap
_, err = m.Put(context.Background(), "foo", "bar")
if err != nil {
    ...
}

// Write to the multimap
_, err = m.Put(context.Background(), "foo", "baz")
if err != nil {
    ...
}

// Read from the multimap
values, err := m.Get(context.Background(), "foo")
if err != nil {
    ...
}
// Get a string set
l, err := atomix.Set[string]("my-set").
    Codec(generic.Scalar[string]()).
    Get(context.Background())
if err != nil {
    ...
}

// Add a value to the set
err = l.Add(context.Background(), "Hello world!")
if err != nil {
    ...
}

// Check if the set contains the added value
if ok, err := l.Contains(context.Background()); err != nil {
    ...
} else if ok {
    ...
}
// Get a string value
v, err := atomix.Value[string]("my-value").
    Codec(generic.Scalar[string]()).
    Get(context.Background())
if err != nil {
    ...
}

// Set the value
err = v.Set(context.Background(), "Hello world!")
if err != nil {
    ...
}

// Get the value
value, err := v.Get(context.Background())
if err != nil {
    ...
}
// Get the "foo" counter
AtomicCounter counter = AtomicCounter.builder()
    .withName("foo")
    .build();

// Increment the counter
long value = counter.incrementAndGet();

// Get the counter value
value = counter.get();
// Get the "foo" map
Map<String, String> map = AtomicMap.builder()
    .withName("foo")
    .withSerializer(mySerializer)
    .build();

// Write to the map
map.put("foo", "bar");

// Read from the map
Entry<string, string> entry = map.get("foo");

Deploy data stores

The Atomix runtime API acts as an abstraction layer for data stores, decoupling your application’s code from specific databases and protocols, and enabling developers to choose the tools they like without concern for vendor lock-in.

Learn more

apiVersion: consensus.atomix.io/v1beta1
kind: ConsensusStore
metadata:
  name: my-consensus-store
spec:
  replicas: 3
  groups: 30

Coming soon!

Coming soon!

apiVersion: podmemory.atomix.io/v1beta1
kind: PodMemoryStore

Coming soon!

apiVersion: sharedmemory.atomix.io/v1beta1
kind: SharedMemoryStore

Wire everything together

Atomix is designed around the same principles of cloud-native architecture that are familiar to Kubernetes developers. Storage is defined for each application via the StorageProfile custom resource. A tag-based routing system enables applications to use multiple data stores while allowing application developers and their users to optimize applications and the atoms within them without having to change a single line of code.

Learn more

apiVersion: atomix.io/v3beta3
kind: StorageProfile
metadata:
  name: my-application-profile
spec:
  bindings:
    - store:
        name: consensus-store
      tags:
        - my-app
        - persistent
    - store:
        name: cache-store
      tags:
        - my-app
        - volatile

Want to contribute?

We're seeking contributors for new primitives, SDKs, and data stores. Do you know a language Atomix doesn't support yet? Is there a database you want to integrate with Atomix? Do you have a use case for a new type of primitive? Visit the contributor guide to get started!

Together, we can make distributed systems accessible for everyone!

Learn more