Current section

Files

Jump to
ex_esdb home rl work github.com beam-campus ex-esdb README.md
Raw

home/rl/work/github.com/beam-campus/ex-esdb/README.md

# ExESDB - A BEAM-native Event Store
`ExESDB` is a BEAM-native Event Store, built on top of the [khepri](https://github.com/rabbitmq/khepri) and [ra](https://github.com/rabbitmq/ra) subsystems.
## Motivation
One of the arguments for BEAM development is that it comes "batteries included". Be it caching, storage, pub/sub, observability etc... the Erlang ecosystem always has the option to avoid external dependencies.
For Event Sourcing use cases however, the Event Store is often a separate service.
This project is an attempt at addressing this point, by building further upon the work of the `rabbitmq/khepri` and `rabbitmq/ra` subsystems.
## Features
ExESDB is a distributed, BEAM-native Event Store that provides high-availability event sourcing capabilities with automatic cluster formation and coordination. Built on top of Khepri and Ra (Raft consensus), it offers enterprise-grade reliability and performance.
### Core Event Store Functionality
#### Event Stream Management
- **Stream Creation**: Automatic stream creation on first event append
- **Event Appending**: Atomic append operations with optimistic concurrency control
- **Event Retrieval**: Query events with forward/backward traversal support
- **Stream Versioning**: Track stream versions for conflict detection and resolution
- **Stream Listing**: Enumerate all streams in the store
#### Event Storage
- **Persistent Storage**: Durable event storage using Khepri's distributed key-value store
- **ACID Compliance**: Atomic, consistent, isolated, and durable operations
- **Conflict Resolution**: Built-in optimistic concurrency control
- **Data Integrity**: Checksum validation and corruption detection
#### Subscription System
- **Multiple Subscription Types**:
- `:by_stream` - Subscribe to specific event streams
- `:by_event_type` - Subscribe to events by type classification
- `:by_event_pattern` - Pattern-based event matching
- `:by_event_payload` - Content-based subscription filtering
- **Persistent Subscriptions**: Durable subscriptions that survive node restarts
- **Transient Subscriptions**: Temporary subscriptions for real-time processing
- **Event Replay**: Start subscriptions from any stream version
- **Acknowledgment System**: Reliable event delivery with ACK/NACK support
- **"Follow-the-Leader"**: Subscription processes automatically migrate to cluster leader
#### Snapshot Management
- **Aggregate Snapshots**: Store and retrieve aggregate state snapshots
- **Version-based Snapshots**: Snapshots tied to specific stream versions
- **Snapshot Lifecycle**: Create, read, update, and delete snapshot operations
- **Performance Optimization**: Reduce replay time for large aggregates
- **Distributed Storage**: Snapshots stored across the cluster for availability
### Distributed Architecture & Clustering
#### LibCluster Integration
ExESDB uses LibCluster for automatic cluster discovery and formation:
- **Strategy**: Gossip-based multicast discovery
- **Protocol**: UDP multicast on configurable port (default: 45892)
- **Network**: Automatic node discovery on shared networks
- **Security**: Shared secret authentication for cluster membership
- **Broadcast Discovery**: Configurable multicast addressing
#### Cluster Formation Process
1. **Initialization**: Node starts and initializes LibCluster topology
2. **Discovery**: Uses gossip multicast to discover peer nodes
3. **Authentication**: Validates cluster membership using shared secrets
4. **Coordination**: ClusterCoordinator manages join/leave operations
5. **Consensus**: Khepri cluster formation using Raft consensus
6. **Monitoring**: Continuous health monitoring and leader election
#### High Availability Features
- **Automatic Clustering**: Nodes automatically discover and join clusters
- **Split-Brain Prevention**: ClusterCoordinator prevents network partition issues
- **Leader Election**: Automatic leader election using Raft consensus
- **Failover**: Seamless handling of node failures
- **Data Replication**: Events replicated across cluster nodes
- **Consensus Protocol**: Ra/Raft ensures data consistency
### Storage Engine
#### Khepri Integration
- **Distributed Tree Store**: Hierarchical key-value storage
- **MVCC**: Multi-version concurrency control
- **Transactions**: ACID transaction support
- **Schema Evolution**: Support for data structure changes
- **Triggers**: Event-driven data processing
#### Ra (Raft) Consensus
- **Strong Consistency**: Linearizable read/write operations
- **Partition Tolerance**: Operates correctly during network partitions
- **Leader-based Replication**: Single leader for write operations
- **Log Compaction**: Automatic cleanup of old log entries
- **Snapshot Support**: Efficient state transfer for new nodes
### Configuration & Deployment
#### Environment Configuration
- `EX_ESDB_STORE_ID`: Unique identifier for the store instance
- `EX_ESDB_DB_TYPE`: Deployment type (`:single` or `:cluster`)
- `EX_ESDB_DATA_DIR`: Data directory for persistent storage
- `EX_ESDB_TIMEOUT`: Operation timeout configuration
- `EX_ESDB_CLUSTER_SECRET`: Shared secret for cluster authentication
- `EX_ESDB_COOKIE`: Erlang distribution cookie
- `EX_ESDB_PUB_SUB`: PubSub configuration for event broadcasting
#### LibCluster Configuration
```elixir
config :libcluster,
topologies: [
ex_esdb_cluster: [
strategy: Cluster.Strategy.Gossip,
config: [
port: 45_892,
if_addr: "0.0.0.0",
multicast_addr: "255.255.255.255",
broadcast_only: true,
secret: System.get_env("EX_ESDB_CLUSTER_SECRET")
]
]
]
```
### Gateway API Integration
#### High-Availability Proxy
- **Load Balancing**: Distribute requests across gateway workers
- **Service Discovery**: Automatic discovery of available gateway workers
- **Fault Tolerance**: Handle worker failures gracefully
- **Request Routing**: Smart routing based on operation type
#### Worker Distribution
- **Swarm Integration**: Distributed worker management
- **Process Migration**: Workers can move between cluster nodes
- **Resource Management**: Efficient resource utilization across cluster
- **Monitoring**: Real-time worker health and performance tracking
### Operational Features
#### Monitoring & Observability
- **Cluster Status**: Real-time cluster membership and health
- **Leader Tracking**: Monitor current cluster leader
- **Performance Metrics**: Operation latency and throughput
- **Error Tracking**: Comprehensive error logging and reporting
- **Health Checks**: Built-in health check endpoints
#### Development Tools
- **Cluster Manager**: Interactive cluster management script
- **Docker Compose**: Multi-node development environment
- **Chaos Engineering**: Built-in chaos testing capabilities
- **Validation Scripts**: Automated cluster validation tools
### Network Topology
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ ExESDB Node │ │ ExESDB Node │ │ ExESDB Node │
│ (Leader) │◄──►│ (Follower) │◄──►│ (Follower) │
│ Khepri + Ra │ │ Khepri + Ra │ │ Khepri + Ra │
└─────────────────┘ └─────────────────┘ └─────────────────┘
▲ ▲ ▲
│ │ │
│ Gossip Multicast Network (UDP:45892) │
│ │ │
▼ ▼ ▼
Raft Consensus Event Storage Subscription
& Replication & Retrieval Management
```
### Deployment Scenarios
#### Single Node Deployment
- **Development**: Local development and testing
- **Small Applications**: Simple event sourcing needs
- **Embedded Usage**: Integration within existing applications
#### Multi-Node Cluster
- **Production**: High-availability production deployments
- **Horizontal Scaling**: Scale read/write capacity
- **Geographic Distribution**: Multi-region deployments
- **Fault Tolerance**: Survive individual node failures
#### Container Orchestration
- **Docker Compose**: Development and testing environments
- **Kubernetes**: Production container orchestration
- **Docker Swarm**: Simplified container clustering
- **Health Checks**: Container-level health monitoring
### Performance Characteristics
#### Throughput
- **Write Performance**: Optimized for high-volume event appending
- **Read Performance**: Efficient event retrieval and streaming
- **Concurrent Operations**: Handle multiple simultaneous operations
- **Batch Processing**: Support for batch event operations
#### Scalability
- **Horizontal Scaling**: Add nodes to increase capacity
- **Storage Scalability**: Distributed storage across cluster
- **Subscription Scaling**: Distribute subscription load
- **Resource Utilization**: Efficient use of available resources
### Integration Capabilities
#### BEAM Ecosystem
- **Phoenix Integration**: Real-time web applications
- **LiveView Support**: Real-time UI updates
- **GenServer Integration**: Native BEAM process integration
- **OTP Supervision**: Fault-tolerant supervision trees
#### External Systems
- **REST APIs**: HTTP-based integration
- **Message Queues**: Integration with external queuing systems
- **Databases**: Projection and read model support
- **Monitoring Systems**: Metrics and alerting integration
## Installation
### Docker Installation
ExESDB is available as a Docker image on Docker Hub with automatic versioning based on the `mix.exs` version.
#### Available Tags
- `beamcampus/ex_esdb:latest` - Latest build from master branch
- `beamcampus/ex_esdb:0.0.18` - Specific version (current version)
- `beamcampus/ex_esdb:0.0.x` - Any specific version tag
#### Quick Start
**Single Node:**
```bash
docker run -d \
--name ex-esdb \
-p 4369:4369 \
-p 9000-9100:9000-9100 \
-p 45892:45892/udp \
-e EX_ESDB_STORE_ID="my-store" \
-e EX_ESDB_DB_TYPE="single" \
-e EX_ESDB_DATA_DIR="/data" \
-v ex-esdb-data:/data \
beamcampus/ex_esdb:latest
```
**Multi-Node Cluster:**
```bash
# Node 1 (seed node)
docker run -d \
--name ex-esdb-node1 \
--network ex-esdb-net \
-p 4369:4369 \
-p 9001:9000 \
-p 45892:45892/udp \
-e EX_ESDB_STORE_ID="cluster-store" \
-e EX_ESDB_DB_TYPE="cluster" \
-e EX_ESDB_DATA_DIR="/data" \
-e EX_ESDB_CLUSTER_SECRET="your-secret-key" \
-e EX_ESDB_COOKIE="your-erlang-cookie" \
-v ex-esdb-node1-data:/data \
beamcampus/ex_esdb:latest
# Node 2
docker run -d \
--name ex-esdb-node2 \
--network ex-esdb-net \
-p 9002:9000 \
-e EX_ESDB_STORE_ID="cluster-store" \
-e EX_ESDB_DB_TYPE="cluster" \
-e EX_ESDB_DATA_DIR="/data" \
-e EX_ESDB_CLUSTER_SECRET="your-secret-key" \
-e EX_ESDB_COOKIE="your-erlang-cookie" \
-v ex-esdb-node2-data:/data \
beamcampus/ex_esdb:latest
# Node 3
docker run -d \
--name ex-esdb-node3 \
--network ex-esdb-net \
-p 9003:9000 \
-e EX_ESDB_STORE_ID="cluster-store" \
-e EX_ESDB_DB_TYPE="cluster" \
-e EX_ESDB_DATA_DIR="/data" \
-e EX_ESDB_CLUSTER_SECRET="your-secret-key" \
-e EX_ESDB_COOKIE="your-erlang-cookie" \
-v ex-esdb-node3-data:/data \
beamcampus/ex_esdb:latest
```
#### Docker Compose
For development and testing, use the provided Docker Compose setup:
```bash
# Clone the repository
git clone https://github.com/beam-campus/ex-esdb.git
cd ex-esdb/dev-env
# Start a 3-node cluster
./start-core-only.sh
# Or use the interactive cluster manager
./ez-cluster.sh
```
The Docker Compose setup includes:
- **Core Cluster**: 3-node ExESDB cluster (ex-esdb0, ex-esdb1, ex-esdb2)
- **Extended Tier**: Additional 2 nodes (ex-esdb10, ex-esdb11)
- **Massive Tier**: Additional 8 nodes (ex-esdb20-27)
- **Automatic Networking**: Configured Docker networks for cluster communication
- **Data Persistence**: Named volumes for data persistence
- **Health Checks**: Built-in container health monitoring
#### Environment Variables
> **📌 Important**: When using the dev-env Docker Compose configurations, you must export the `EX_ESDB_COOKIE` environment variable on your host machine. This single environment variable is used for all cluster authentication purposes (cookies, secrets, etc.).
>
> ```bash
> export EX_ESDB_COOKIE="your-secure-cookie-value"
> ```
| Variable | Description | Default | Required |
|----------|-------------|---------|----------|
| `EX_ESDB_STORE_ID` | Unique store identifier | - | Yes |
| `EX_ESDB_DB_TYPE` | Deployment type (`single` or `cluster`) | `single` | No |
| `EX_ESDB_DATA_DIR` | Data directory path | `/data` | No |
| `EX_ESDB_TIMEOUT` | Operation timeout (ms) | `5000` | No |
| `EX_ESDB_CLUSTER_SECRET` | Cluster authentication secret | - | Yes (cluster) |
| `EX_ESDB_COOKIE` | Erlang distribution cookie | - | Yes (cluster) |
| `EX_ESDB_PUB_SUB` | PubSub process name | `:ex_esdb_pubsub` | No |
#### Ports
| Port | Protocol | Description |
|------|----------|-------------|
| `4369` | TCP | EPMD (Erlang Port Mapper Daemon) |
| `9000-9100` | TCP | Erlang distribution ports |
| `45892` | UDP | LibCluster gossip multicast |
#### Health Checks
The Docker image includes a built-in health check script:
```bash
# Check container health
docker exec ex-esdb ./check-ex-esdb.sh
# View health status
docker inspect --format='{{.State.Health.Status}}' ex-esdb
```
#### Production Considerations
1. **Security**: Use strong, unique values for `EX_ESDB_CLUSTER_SECRET` and `EX_ESDB_COOKIE`
2. **Networking**: Ensure proper firewall rules for cluster communication
3. **Storage**: Use named volumes or bind mounts for data persistence
4. **Monitoring**: Implement external monitoring for cluster health
5. **Backups**: Regular backup of data volumes
6. **Resource Limits**: Set appropriate CPU and memory limits
### Hex Installation
ExESDB is also available as a Hex package for direct integration:
```elixir
def deps do
[
{:ex_esdb, "~> 0.0.18"}
]
end
```
## Contents
- [Getting Started](system/guides/getting_started.md)
## Releases
- [On Hex](https://hex.pm/packages/ex_esdb)
- [Release Documentation](https://hexdocs.pm/ex_esdb/index.html)