Languages: English | 繁體中文
Babuza turns etcd Raft into an embeddable Go framework for production services. It provides the Raft runtime, WAL, snapshots, transport, sessions, cluster operations, and integration test harness you otherwise have to build around etcd/raft yourself.
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.
| Feature | What Babuza Provides |
|---|---|
| Raft Runtime | Ready-loop processing, proposal handling, linearizable reads, and lifecycle management |
| WAL Backends | Native Babuza WAL, etcd WAL, Badger, and Pebble options |
| Snapshot Management | Durable, volatile, and S3-compatible snapshot storage with chunked transfer |
| Transport Layer | Pluggable TCP, HTTP, and gRPC transports, including HTTP stream mode |
| Client Sessions | Optional exactly-once semantics through no-op, expiring, or LRU session managers |
| Cluster Operations | Add/remove/update peers, promote learners, transfer leadership, and disaster recovery |
| Testing Harness | Multi-node testcluster support with partitions, node failures, restarts, and fault injection |
| Observability | Prometheus and OpenTelemetry integration points |
| 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% |
Babuza stores log entry metadata in memory and reads entry payloads from WAL on demand, so memory usage stays mostly independent of entry data size. See the full Memory Usage Benchmark Report.
HTTP transport supports an opt-in stream mode that reuses long-lived HTTP request bodies for framed Raft messages and snapshot chunks. In local benchmarks, stream mode significantly reduces per-message request overhead:
| Workload | Short Request | HTTP Stream | Improvement |
|---|---|---|---|
| Batch message | 26.806 us/op | 2.349 us/op | 11.4x faster |
| Snapshot, 32 x 256 B chunks | 990.327 us/op | 148.066 us/op | 6.7x faster |
| Snapshot, 4 x 8 KiB chunks | 175.458 us/op | 90.616 us/op | 1.9x faster |
See the full HTTP Stream Benchmark Comparison for benchmark details and allocation results.
package main
import (
"context"
"encoding/json"
"fmt"
"sync"
"time"
"github.com/fanaujie/babuza/ibabuza"
"github.com/fanaujie/babuza/raft"
)
// 1. Implement your state machine
type KVStore struct {
mu sync.RWMutex
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.mu.Lock()
s.data[cmd.Key] = cmd.Value
s.mu.Unlock()
return ibabuza.ApplyResult{LogIndex: e.Index}
}
func (s *KVStore) Query(key any) (any, error) {
s.mu.RLock()
defer s.mu.RUnlock()
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 |
| 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 |
The raft/experimental package implements multi-Raft group support without modifying the upstream etcd Raft library:
- 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
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