A Go framework built on etcd Raft that simplifies building distributed consensus-based systems.
Building distributed systems with Raft is hard. While etcd provides a battle-tested Raft implementation, using it directly requires significant effort:
- Raft Ready Loop: You must implement a goroutine to process
Ready()structs, handle entries, messages, snapshots, and hard state persistence in the correct order - Storage Integration: WAL and snapshot storage must be carefully coordinated - write entries before sending messages, apply snapshots atomically
- Network Layer: Build your own transport to send/receive Raft messages between peers, handle connection failures and retries
- State Machine Lifecycle: Manage snapshot creation, restoration, and log compaction while ensuring consistency
- Cluster Membership: Implement protocol for adding/removing nodes, handling joint consensus, and learner promotion
| Challenge | etcd Raft | Babuza |
|---|---|---|
| Memory Management | Keeps all log entries in memory | Index-based caching saves 94-99% memory |
| Network Transport | Basic HTTP transport provided | Pluggable TCP/HTTP/gRPC transports |
| WAL | etcd WAL provided | Multiple backends: native, Badger, Pebble |
| Snapshot Transfer | Full transfer via HTTP | Compressed & chunked transfer with rate limiting |
| Cluster Operations | Manual peer management | Built-in add/remove/transfer APIs |
| Idempotency | Application handles dedup | Session-based exactly-once semantics |
| Observability | Roll your own | Prometheus & OpenTelemetry built-in |
| Disaster Recovery | Complex manual process | One-command standalone restoration |
| Integration Testing | Write your own test harness | testcluster with fault injection & partition simulation |
Babuza lets you focus on your application logic, not Raft plumbing.
| Entries | Data Size | etcd Memory | Babuza Memory | Saved |
|---|---|---|---|---|
| 100K | 1 KB | 102 MB | 5.35 MB | 94.8% |
| 100K | 10 KB | 981 MB | 5.35 MB | 99.5% |
See the full Memory Usage Benchmark Report for detailed analysis.
The experimental package implements multi-Raft group support:
- Coalesced Heartbeats - Merge heartbeats from multiple Raft groups to reduce network overhead
- Shared WAL - Multiple Raft groups share a single WAL instance
- Sharded Scheduling - Efficient processing across many Raft groups
- All implemented without any modifications to the etcd Raft library
package main
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/fanaujie/babuza/ibabuza"
"github.com/fanaujie/babuza/raft"
)
// 1. Implement your state machine
type KVStore struct{ data map[string]string }
func (s *KVStore) Apply(e ibabuza.Entry) ibabuza.ApplyResult {
var cmd struct{ Key, Value string }
json.Unmarshal(e.Command, &cmd)
s.data[cmd.Key] = cmd.Value
return ibabuza.ApplyResult{LogIndex: e.Index}
}
func (s *KVStore) Query(key any) (any, error) { return s.data[key.(string)], nil }
func (s *KVStore) SaveSnapshot(ibabuza.StateMachineSnapshotContext, ibabuza.StateMachineSnapshotWriter) error { return nil }
func (s *KVStore) RestoreFromSnapshot(ibabuza.StateMachineSnapshotReader) error { return nil }
func (s *KVStore) Close() error { return nil }
func main() {
// 2. Start Raft with default settings
r, _ := raft.NewDefaultBuilder().
DataDir("/tmp/babuza").
StateMachine(&KVStore{data: make(map[string]string)}).
Start()
// 3. Wait for leader election
time.Sleep(2 * time.Second)
// 4. Propose data through Raft consensus
data, _ := json.Marshal(map[string]string{"Key": "hello", "Value": "world"})
r.Propose(context.Background(), raft.ClientSession{}, data).WaitForApplyResult()
fmt.Println("Data committed through Raft consensus!")
r.Shutdown().Wait()
}| Example | Description |
|---|---|
| Simple | Minimal single-node Raft example |
| KV Store | Single-raft distributed key-value store with REST API |
| Distributed Lock | Lease-based distributed lock with fencing tokens and wait queue |
| Redis Cluster | Multi-raft Redis-compatible distributed cache |
Use babuza-skills to enhance AI coding assistants (Claude Code, Cursor, Aider) with Babuza-specific knowledge for code generation and explanations.
| Package | Description |
|---|---|
| ibabuza | Core interfaces for all pluggable components |
| raft | Consensus layer, cluster bootstrap, and Raft API |
| raft/experimental | Multi-Raft with coalesced heartbeats and shared WAL (experimental) |
| pkg/builder | Component builder pattern for easy assembly |
| Package | Description |
|---|---|
| pkg/cluster | Cluster membership and peer management |
| pkg/transport | Network transport layer (TCP, HTTP, gRPC) |
| pkg/session | Client session management for idempotency |
| pkg/snapshot | Snapshot creation, storage, and restoration |
| pkg/wal | Write-ahead log implementations |
| Component | Available Types |
|---|---|
| Session | noop, expire, lru |
| Transport | tcp, tcp-memory, http, grpc |
| WAL | babuza-wal, etcd-wal, badger-wal, badger-wal-memory, pebble-wal, pebble-wal-memory |
| Snapshot | durable, volatile, s3 |
| Metrics | otel, prometheus |
Babuza provides a testcluster framework for testing distributed system failure scenarios:
Supported Failure Scenarios:
| Scenario | Description |
|---|---|
| Node Disconnect | Simulate single node network failure |
| Network Partition | Split cluster into isolated groups |
| Leader Failure | Stop/restart leader node |
| Quorum Loss | Disconnect majority of nodes |
| Node Restart | Stop and restart with WAL/snapshot recovery |
| Disaster Recovery | Recover standalone from lost cluster |
Contributions are welcome! Please ensure:
- Tests are included for new functionality
- Documentation is updated as needed
Apache License 2.0. See LICENSE for details.
Copyright 2025 Chen Chunchieh