gossipkv

package module
v0.2.0-beta Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2026 License: MIT Imports: 13 Imported by: 0

README

Gossip-KV: Embedded, decentralized key-value database in Go

Status: experimental

Gossip-KV is an embedded Go library that lets you build decentralized clusters to exchange simple key-value data. It uses a gossip protocol to synchronize data between nodes without external dependencies.

Why does this exist?

Many distributed systems need to exchange simple data such as configuration, service discovery metadata, or feature flags. Often this requires running and maintaining external services like Redis or etcd.

Gossip-KV solves this by providing a lightweight, self-contained, fault-tolerant mechanism right inside your Go application.

Key features
  • Embedded: a library, not a separate server.
  • Decentralized: no master node, all nodes are peers.
  • Eventual consistency: data converges over time.
  • Simple API: Set/Get with context support.
  • Flexible types: generic API K ~string, V any.
  • UDP replication: lightweight gossip cycles.
Technology
  • Go (generics) for type-safe API.
  • Gossip anti-entropy: digest + delta.
  • UDP transport for lightweight replication.
  • LWW merge: conflict resolution by time/version.
  • In-memory storage with no external dependencies.
  • Codecs: gob by default, fast BytesCodec/StringCodec options.
How it works
  1. Each node stores data locally in memory.
  2. Periodically, a random peer is selected.
  3. The node sends a digest (keys + versions).
  4. The receiver computes a delta and returns missing records.
  5. Records are merged using LWW.
Configuration and modes

All parameters are configured via Option in New(...). Below is the behavior and defaults.

WithNodeID(string)

  • Sets a stable node identifier.
  • If not provided, a random ID is generated.
  • Used for conflict resolution and diagnostics.

WithBindAddr("host:port")

  • Enables network mode (UDP gossip) and binds the socket.
  • If not set, the node runs locally (no gossip).
  • Required if Seeds are provided.

WithSeeds([]string)

  • List of peer addresses (bootstrap).
  • Empty list means no replication.
  • You can pass all known peer addresses.

WithGossipInterval(time.Duration)

  • Digest/delta exchange interval.
  • Default is 2s.
  • Lower values increase load but converge faster.

WithDiscovery(bool)

  • Enables mDNS discovery on the local network.
  • Defaults to false.
  • Requires WithBindAddr so the node can announce itself.

WithCodec(codec)

  • Serialization codec used for gossip.
  • Default is GobCodec.
  • For maximum speed use:
    • BytesCodec for []byte
    • StringCodec for string

WithErrorHandler(func(error))

  • Callback for internal errors (serialize/network).
  • Best-effort, must be fast and non-blocking.

Default behavior (no options)

  • Local in-memory database.
  • No network replication.
  • Random NodeID.
Use cases
  • Configuration propagation between service instances.
  • Feature flags without external storage.
  • Discovery/metadata in local clusters.
  • Caches where eventual consistency is acceptable.
Limitations
  • No strong consistency (eventual consistency only).
  • No persistence (in-memory only).
  • No built-in auth/encryption.
  • mDNS discovery is LAN-only; for cross-network use explicit seeds.
Package layout
  • gossipkv/ — public API.
  • internal/gossip/ — gossip protocol and transport.
  • internal/storage/ — storage and merge logic.
Quick start
  1. Установка

    go get github.com/DobryySoul/gossipkv
    
  2. Использование

    Initialize the database and start using it.

    package main
    
    import (
        "context"
        "fmt"
        "github.com/DobryySoul/gossipkv"
    )
    
    func main() {
        // Create a new node.
        db, err := gossipkv.New[string, string]()
        if err != nil {
            // handle error
        }
    
        // Set a value
        err = db.Set(context.Background(), "version", "v1.0.1")
        if err != nil {
            // handle error
        }
    
        // Get a value
        value, err := db.Get(context.Background(), "version")
        if err != nil {
            // handle error
        }
    
        fmt.Println("value:", value)
    }
    
Manual peer setup (no discovery)

To exchange data between nodes, provide a bind address and a list of peers.

db, err := gossipkv.New[string, string](
    gossipkv.WithNodeID("node-a"),
    gossipkv.WithBindAddr("127.0.0.1:9001"),
    gossipkv.WithSeeds([]string{
        "127.0.0.1:9002",
        "127.0.0.1:9003",
    }),
)

Documentation

Overview

Package gossipkv provides an embedded, decentralized key-value store with an eventual-consistency gossip protocol.

Overview

gossipkv is designed for simple, low-latency data sharing between service instances without external dependencies. Nodes exchange updates using a lightweight gossip cycle (digest + delta) over UDP.

Data model

Records are versioned and merged using a last-write-wins (LWW) strategy based on UpdatedAt, Version, and NodeID. This provides eventual consistency with minimal coordination overhead.

Generics

The DB type is generic over key and value types. Keys must be string or a type with underlying string. Values can be any type.

Networking

Gossip is enabled when a bind address is provided. Without a bind address, the database works in local in-memory mode.

Serialization

Values are serialized for transport using a Codec. The default is GobCodec, while BytesCodec and StringCodec provide faster binary encoding for []byte and string values.

Example

db, err := gossipkv.New[string, string](
	gossipkv.WithBindAddr("127.0.0.1:9001"),
	gossipkv.WithSeeds([]string{"127.0.0.1:9002"}),
	gossipkv.WithCodec(gossipkv.StringCodec{}),
)
if err != nil {
	// handle error
}
_ = db.Set(context.Background(), "key", "value")
_, _ = db.Get(context.Background(), "key")

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound indicates that the requested key is missing.
	ErrNotFound = errors.New("gossipkv: key not found")
	// ErrClosed indicates that the DB has been closed.
	ErrClosed = errors.New("gossipkv: db is closed")
	// ErrTimeout indicates that the context deadline expired.
	ErrTimeout = errors.New("gossipkv: operation timed out")
	// ErrCanceled indicates that the context was canceled.
	ErrCanceled = errors.New("gossipkv: operation canceled")
)

Functions

This section is empty.

Types

type BytesCodec

type BytesCodec struct{}

BytesCodec passes through raw bytes without copying. The caller must not modify the returned slice.

func (BytesCodec) Marshal

func (BytesCodec) Marshal(value []byte) ([]byte, error)

func (BytesCodec) Unmarshal

func (BytesCodec) Unmarshal(data []byte) ([]byte, error)

type Codec

type Codec[V any] interface {
	Marshal(value V) ([]byte, error)
	Unmarshal(data []byte) (V, error)
}

Codec serializes values for transport between nodes.

type Config

type Config struct {
	NodeID         string
	BindAddr       string
	Seeds          []string
	Discovery      bool
	GossipInterval time.Duration
	// contains filtered or unexported fields
}

Config holds runtime configuration for a gossipkv node. Users typically set it via Option helpers.

type DB

type DB[K ~string, V any] struct {
	// contains filtered or unexported fields
}

DB represents a running gossipkv node. It is safe for concurrent use by multiple goroutines. K must be a string or a type with underlying string.

func New

func New[K ~string, V any](opts ...Option) (*DB[K, V], error)

New creates a new gossipkv node with the provided options. The returned instance uses an in-memory store in the current version. K must be provided explicitly because it cannot be inferred from arguments.

func (*DB[K, V]) Close

func (db *DB[K, V]) Close(ctx context.Context) error

Close releases resources and marks the DB as closed. Further operations will return ErrClosed. The provided context allows cancellation of the close operation.

func (*DB[K, V]) Get

func (db *DB[K, V]) Get(ctx context.Context, key K) (V, error)

Get returns a value for the given key. It returns ErrNotFound if the key does not exist.

func (*DB[K, V]) Set

func (db *DB[K, V]) Set(ctx context.Context, key K, value V) error

Set stores a value under the given key. The call is context-aware and returns ErrCanceled/ErrTimeout accordingly.

type GobCodec

type GobCodec[V any] struct{}

GobCodec uses encoding/gob for serialization. It works with most Go types without extra registration.

func (GobCodec[V]) Marshal

func (GobCodec[V]) Marshal(value V) ([]byte, error)

func (GobCodec[V]) Unmarshal

func (GobCodec[V]) Unmarshal(data []byte) (V, error)

type Option

type Option func(*Config) error

Option configures the database on creation. Return an error to reject an invalid option value.

func WithBindAddr

func WithBindAddr(addr string) Option

WithBindAddr sets the local bind address in host:port form. It is validated with net.SplitHostPort.

func WithCodec

func WithCodec[V any](codec Codec[V]) Option

WithCodec sets the value codec used by gossip transport.

func WithDiscovery

func WithDiscovery(enabled bool) Option

WithDiscovery enables or disables discovery mechanisms like mDNS.

func WithErrorHandler

func WithErrorHandler(handler func(error)) Option

WithErrorHandler sets a callback for internal errors (serialization, network). It is best-effort and must be fast and non-blocking.

func WithGossipInterval

func WithGossipInterval(interval time.Duration) Option

WithGossipInterval sets how often the node exchanges gossip updates.

func WithNodeID

func WithNodeID(nodeID string) Option

WithNodeID sets a stable node identifier used in gossip metadata. If omitted, a random ID is generated.

func WithSeeds

func WithSeeds(seeds []string) Option

WithSeeds sets the initial seed node addresses for bootstrapping.

type StringCodec

type StringCodec struct{}

StringCodec encodes strings as raw bytes. It allocates on marshal/unmarshal to keep data immutable.

func (StringCodec) Marshal

func (StringCodec) Marshal(value string) ([]byte, error)

func (StringCodec) Unmarshal

func (StringCodec) Unmarshal(data []byte) (string, error)

Directories

Path Synopsis
examples
basic command
bytes_codec command
custom_type command
gossip_peer command
string_codec command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL