RedHub is a high-performance RESP (Redis Serialization Protocol) server framework built in Go. It leverages the RawEpoll model via the gnet library to achieve ultra-high throughput with multi-threaded support while maintaining low CPU resource consumption.
- Ultra High Performance - Exceeds Redis single-threaded and multi-threaded implementations in benchmarks
- Fully Multi-threaded - Native support for multiple CPU cores with efficient event loop distribution
- Low Resource Consumption - Optimized memory usage and CPU efficiency
- Full RESP Protocol Support - Compatible with Redis protocol (RESP2)
- Multi-Protocol Support - Supports RESP, Tile38 native, and Telnet protocols
- Easy to Use - Create Redis-compatible servers with minimal code
- Production Ready - Robust error handling, connection management, and extensibility
RedHub implements an event-driven architecture based on the gnet framework:
┌─────────────────────────────────────────────────────────────┐
│ Client Connections │
└─────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Event Loops (gnet) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Event Loop 1│ │ Event Loop 2│ │ Event Loop N│ │
│ │ (Thread 1) │ │ (Thread 2) │ │ (Thread N) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ RedHub Core │ │
│ │ Handler │ │
│ └──────┬───────┘ │
└───────────────────────────┼──────────────────────────────────┘
│
▼
┌─────────────────┐
│ Application │
│ Logic & Storage │
└─────────────────┘
- Single-core mode: All connections handled by a single event loop
- Multi-core mode: Multiple event loops distribute connections using configurable load balancing strategies
- Connection Buffering: Each connection maintains its own buffer for command accumulation
- Thread Safety: Uses RWMutex for connection map synchronization
go get -u github.com/IceFireDB/redhubHere's a simple example showing how to create a Redis-compatible server with SET, GET, DEL, PING, and QUIT commands:
package main
import (
"log""strings""sync""github.com/IceFireDB/redhub""github.com/IceFireDB/redhub/pkg/resp"
)
funcmain() {
varmu sync.RWMutexvaritems=make(map[string][]byte)
// Create a new RedHub instancerh:=redhub.NewRedHub(
// OnOpen: Called when a new connection is establishedfunc(c*redhub.Conn) (out []byte, action redhub.Action) {
// Initialize connection-specific data herereturnnil, redhub.None
},
// OnClose: Called when a connection is closedfunc(c*redhub.Conn, errerror) (action redhub.Action) {
// Clean up connection-specific data herereturnredhub.None
},
// Handler: Called for each parsed commandfunc(cmd resp.Command, out []byte) ([]byte, redhub.Action) {
// Get command name (case-insensitive)cmdName:=strings.ToLower(string(cmd.Args[0]))
switchcmdName {
case"set":
// SET key valueiflen(cmd.Args) !=3 {
returnresp.AppendError(out, "ERR wrong number of arguments for 'set' command"), redhub.None
}
mu.Lock()
items[string(cmd.Args[1])] =cmd.Args[2]
mu.Unlock()
returnresp.AppendString(out, "OK"), redhub.Nonecase"get":
// GET keyiflen(cmd.Args) !=2 {
returnresp.AppendError(out, "ERR wrong number of arguments for 'get' command"), redhub.None
}
mu.RLock()
val, ok:=items[string(cmd.Args[1])]
mu.RUnlock()
if!ok {
returnresp.AppendNull(out), redhub.None
}
returnresp.AppendBulk(out, val), redhub.Nonecase"del":
// DEL keyiflen(cmd.Args) !=2 {
returnresp.AppendError(out, "ERR wrong number of arguments for 'del' command"), redhub.None
}
mu.Lock()
_, ok:=items[string(cmd.Args[1])]
delete(items, string(cmd.Args[1]))
mu.Unlock()
if!ok {
returnresp.AppendInt(out, 0), redhub.None
}
returnresp.AppendInt(out, 1), redhub.Nonecase"ping":
// PINGreturnresp.AppendString(out, "PONG"), redhub.Nonecase"quit":
// QUITreturnresp.AppendString(out, "OK"), redhub.Closedefault:
// Unknown commandreturnresp.AppendError(out, "ERR unknown command '"+string(cmd.Args[0])+"'"), redhub.None
}
},
)
// Start the servererr:=redhub.ListenAndServe("tcp://127.0.0.1:6379", redhub.Options{
Multicore: true, // Enable multi-core support
}, rh)
iferr!=nil {
log.Fatal(err)
}
}# Navigate to the example directorycd example/memory_kv
# Run the server
go run server.go
# In another terminal, test with redis-cli
redis-cli -p 6379
# Or test with redis-benchmark
redis-benchmark -h 127.0.0.1 -p 6379 -n 1000000 -t set,get -c 512 -P 1024 -qRedHub provides various configuration options through the Options struct:
typeOptionsstruct {
Multicorebool// Enable multi-core support (default: false)LockOSThreadbool// Lock OS thread (default: false)ReadBufferCapint// Read buffer capacity (default: 64KB)LB gnet.LoadBalancing// Load balancing strategy (default: RoundRobin)NumEventLoopint// Number of event loops (default: runtime.NumCPU())ReusePortbool// Enable port reuse (default: false)Tickerbool// Enable ticker (default: false)TCPKeepAlive time.Duration// TCP keep-alive intervalTCPKeepCountint// TCP keep-alive countTCPKeepInterval time.Duration// TCP keep-alive intervalTCPNoDelay gnet.TCPSocketOpt// TCP no-delay optionSocketRecvBufferint// Socket receive buffer sizeSocketSendBufferint// Socket send buffer sizeEdgeTriggeredIObool// Edge-triggered I/O (default: false)
}options:= redhub.Options{
Multicore: true, // Enable multi-coreNumEventLoop: 8, // Use 8 event loopsReadBufferCap: 64*1024, // 64KB read bufferSocketRecvBuffer: 128*1024, // 128KB socket receive bufferSocketSendBuffer: 128*1024, // 128KB socket send bufferTCPKeepAlive: 30*time.Second, // 30s keep-aliveLB: gnet.LeastConnections, // Load balancing strategy
}Action represents the action to take after an event handler completes.
const (
None// No actionClose// Close the connectionShutdown// Shutdown the server
)RedHub is the main server structure that manages connections and command processing.
Conn wraps a gnet.Conn and provides additional functionality for connection management.
Command represents a parsed RESP command with raw bytes and arguments.
typeCommandstruct {
Raw []byte// Raw RESP messageArgs [][]byte// Parsed arguments
}Creates a new RedHub instance with the specified event handlers.
funcNewRedHub(
onOpenedfunc(c*Conn) (out []byte, actionAction),
onClosedfunc(c*Conn, errerror) (actionAction),
handlerfunc(cmd resp.Command, out []byte) ([]byte, Action),
) *RedHubParameters:
onOpened: Called when a new connection is establishedonClosed: Called when a connection is closedhandler: Called for each parsed command
Starts the RedHub server with the specified address and options.
funcListenAndServe(addrstring, optionsOptions, rh*RedHub) errorParameters:
addr: Server address in format "tcp://host:port"options: Server configuration optionsrh: RedHub instance
The resp package provides comprehensive support for the Redis Serialization Protocol (RESP).
const (
Integer=':'// Integers (e.g., :1000\r\n)String='+'// Simple strings (e.g., +OK\r\n)Bulk='$'// Bulk strings (e.g., $6\r\nfoobar\r\n)Array='*'// Arrays (e.g., *2\r\n$3\r\nGET\r\n$3\r\nkey\r\n)Error='-'// Errors (e.g., -ERR unknown command\r\n)
)The resp package provides functions for serializing various Go types to RESP format:
AppendInt(b []byte, n int64) []byte- Append integerAppendString(b []byte, s string) []byte- Append simple stringAppendBulk(b []byte, bulk []byte) []byte- Append bulk bytesAppendBulkString(b []byte, bulk string) []byte- Append bulk stringAppendArray(b []byte, n int) []byte- Append array headerAppendError(b []byte, s string) []byte- Append errorAppendNull(b []byte) []byte- Append null valueAppendOK(b []byte) []byte- Append OK responseAppendAny(b []byte, v interface{}) []byte- Append any Go type
varout []byte// Simple stringout=resp.AppendString(out, "OK")
// Bulk stringout=resp.AppendBulkString(out, "Hello World")
// Integerout=resp.AppendInt(out, 42)
// Arrayout=resp.AppendArray(out, 3)
out=resp.AppendBulkString(out, "item1")
out=resp.AppendBulkString(out, "item2")
out=resp.AppendBulkString(out, "item3")
// Errorout=resp.AppendError(out, "ERR something went wrong")
// Null valueout=resp.AppendNull(out)
// Any typeout=resp.AppendAny(out, map[string]interface{}{
"name": "Redis",
"version": 7.0,
"features": []string{"persistence", "replication"},
})Store connection-specific data using Conn.SetContext():
typeConnectionDatastruct {
AuthenticatedboolDatabaseintClientIDstring
}
onOpened:=func(c*redhub.Conn) (out []byte, action redhub.Action) {
c.SetContext(&ConnectionData{
Authenticated: false,
Database: 0,
ClientID: generateID(),
})
returnnil, redhub.None
}
onClosed:=func(c*redhub.Conn, errerror) (action redhub.Action) {
ctx:=c.Context().(*ConnectionData)
// Cleanup connection datareturnredhub.None
}RedHub naturally supports command pipelining (sending multiple commands in a single network packet):
# Client sends multiple commands in one requestecho -e '*2\r\n$3\r\nSET\r\n$3\r\nkey1\r\n$5\r\nvalue1\r\n*2\r\n$3\r\nSET\r\n$3\r\nkey2\r\n$5\r\nvalue2\r\n*2\r\n$3\r\nGET\r\n$3\r\nkey1\r\n'| nc localhost 6379RedHub supports three protocol types:
- RESP (Redis) - Standard Redis protocol (commands starting with
*) - Tile38 Native - Native Tile38 protocol (commands starting with
$) - Telnet - Plain text commands
OS: Debian Buster 10.6 64bit
CPU: 8 CPU cores
Memory: 64.0 GiB
Go: go1.16.5 linux/amd64
| Implementation | SET (req/sec) | GET (req/sec) |
|---|---|---|
| Redis 5.0.3 (single-threaded) | 2,306,060 | 3,096,742 |
| Redis 6.2.5 (single-threaded) | 2,076,325 | 2,652,801 |
| Redis 6.2.5 (multi-threaded) | 1,944,692 | 2,375,184 |
| RedCon (multi-threaded) | 2,332,742 | 14,654,162 |
| RedHub (multi-threaded) | 4,087,305 | 16,490,765 |
redis-benchmark -h 127.0.0.1 -p 6379 -n 50000000 -t set,get -c 512 -P 1024 -qgo test ./...go test -cover ./...go test -v ./...go test ./pkg/resp/...go test -run TestNewRedHub .- Enable Multi-core: Always enable
Multicore: truein production - Tune Buffer Sizes: Adjust
ReadBufferCap,SocketRecvBuffer, andSocketSendBufferbased on your workload - Choose Load Balancing: Use appropriate load balancing strategy (RoundRobin, LeastConnections, etc.)
- Avoid Blocking: Never block in event handlers - use async operations
- Reuse Buffers: Use buffer pools for temporary allocations
- Shared Data: Always protect shared data with appropriate synchronization (mutexes)
- Connection Context: Use
Conn.SetContext()for per-connection data (thread-safe) - Event Loop Handlers: Handlers execute in event loop threads - avoid heavy computations
- Protocol Errors: Return proper RESP error messages using
resp.AppendError() - Connection Errors: Log errors in
onClosedhandler - Graceful Shutdown: Handle server shutdown properly
We welcome contributions! Please follow these guidelines:
- Fork the repository
- Create a new branch from main/master
- Make your changes with tests
- Ensure all tests pass:
go test ./... - Commit with DCO sign-off:
git commit -s -m "message" - Push to your fork
- Create a pull request
# Clone the repository
git clone https://github.com/IceFireDB/redhub.git
cd redhub
# Install dependencies
go mod download
# Run tests
go test ./...
# Run the example
go run example/memory_kv/server.goThis project is licensed under the MIT License - see the LICENSE file for details.
When you use this software, you agree and acknowledge that the author, maintainer, and contributor of this software are not responsible for any risks, costs, or problems you encounter. If you find a software defect or bug, please submit a patch to help improve it!
- IceFireDB - A distributed database based on RedHub
- gnet - High-performance event-loop networking framework
- GitHub Issues: https://github.com/IceFireDB/redhub/issues
- Discussions: https://github.com/IceFireDB/redhub/discussions


