Skip to content

Repository files navigation

REDHUB

RedHub

GoDoc ReferenceFOSSA StatusGo Report CardLicense

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.

Features

  • 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

Architecture

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 │
└─────────────────┘

Threading Model

  • 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

Installation

go get -u github.com/IceFireDB/redhub

Quick Start

Here's a simple example showing how to create a Redis-compatible server with SET, GET, DEL, PING, and QUIT commands:

Example Code

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)
}
}

Run the Example

# 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 -q

Configuration

RedHub 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)
}

Example Configuration

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
}

API Reference

Core Types

Action

Action represents the action to take after an event handler completes.

const (
None// No actionClose// Close the connectionShutdown// Shutdown the server
)

RedHub

RedHub is the main server structure that manages connections and command processing.

Conn

Conn wraps a gnet.Conn and provides additional functionality for connection management.

Command

Command represents a parsed RESP command with raw bytes and arguments.

typeCommandstruct {
Raw []byte// Raw RESP messageArgs [][]byte// Parsed arguments
}

Main Functions

NewRedHub

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),
) *RedHub

Parameters:

  • onOpened: Called when a new connection is established
  • onClosed: Called when a connection is closed
  • handler: Called for each parsed command

ListenAndServe

Starts the RedHub server with the specified address and options.

funcListenAndServe(addrstring, optionsOptions, rh*RedHub) error

Parameters:

  • addr: Server address in format "tcp://host:port"
  • options: Server configuration options
  • rh: RedHub instance

RESP Protocol Package

The resp package provides comprehensive support for the Redis Serialization Protocol (RESP).

RESP Types

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)
)

RESP Serialization Functions

The resp package provides functions for serializing various Go types to RESP format:

  • AppendInt(b []byte, n int64) []byte - Append integer
  • AppendString(b []byte, s string) []byte - Append simple string
  • AppendBulk(b []byte, bulk []byte) []byte - Append bulk bytes
  • AppendBulkString(b []byte, bulk string) []byte - Append bulk string
  • AppendArray(b []byte, n int) []byte - Append array header
  • AppendError(b []byte, s string) []byte - Append error
  • AppendNull(b []byte) []byte - Append null value
  • AppendOK(b []byte) []byte - Append OK response
  • AppendAny(b []byte, v interface{}) []byte - Append any Go type

Example: Building Responses

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"},
})

Advanced Usage

Connection Context

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
}

Command Pipelining

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 6379

Multi-Protocol Support

RedHub supports three protocol types:

  1. RESP (Redis) - Standard Redis protocol (commands starting with *)
  2. Tile38 Native - Native Tile38 protocol (commands starting with $)
  3. Telnet - Plain text commands

Performance Benchmarks

Test Environment

OS: Debian Buster 10.6 64bit
CPU: 8 CPU cores
Memory: 64.0 GiB
Go: go1.16.5 linux/amd64

Benchmark Results

ImplementationSET (req/sec)GET (req/sec)
Redis 5.0.3 (single-threaded)2,306,0603,096,742
Redis 6.2.5 (single-threaded)2,076,3252,652,801
Redis 6.2.5 (multi-threaded)1,944,6922,375,184
RedCon (multi-threaded)2,332,74214,654,162
RedHub (multi-threaded)4,087,30516,490,765

Benchmark Command

redis-benchmark -h 127.0.0.1 -p 6379 -n 50000000 -t set,get -c 512 -P 1024 -q

REDHUB Benchmarks

REDHUB Benchmarks

Testing

Run All Tests

go test ./...

Run Tests with Coverage

go test -cover ./...

Run Tests with Verbose Output

go test -v ./...

Run Specific Package Tests

go test ./pkg/resp/...

Run Specific Test

go test -run TestNewRedHub .

Best Practices

Performance Optimization

  1. Enable Multi-core: Always enable Multicore: true in production
  2. Tune Buffer Sizes: Adjust ReadBufferCap, SocketRecvBuffer, and SocketSendBuffer based on your workload
  3. Choose Load Balancing: Use appropriate load balancing strategy (RoundRobin, LeastConnections, etc.)
  4. Avoid Blocking: Never block in event handlers - use async operations
  5. Reuse Buffers: Use buffer pools for temporary allocations

Thread Safety

  1. Shared Data: Always protect shared data with appropriate synchronization (mutexes)
  2. Connection Context: Use Conn.SetContext() for per-connection data (thread-safe)
  3. Event Loop Handlers: Handlers execute in event loop threads - avoid heavy computations

Error Handling

  1. Protocol Errors: Return proper RESP error messages using resp.AppendError()
  2. Connection Errors: Log errors in onClosed handler
  3. Graceful Shutdown: Handle server shutdown properly

Contributing

We welcome contributions! Please follow these guidelines:

  1. Fork the repository
  2. Create a new branch from main/master
  3. Make your changes with tests
  4. Ensure all tests pass: go test ./...
  5. Commit with DCO sign-off: git commit -s -m "message"
  6. Push to your fork
  7. Create a pull request

Development Setup

# 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.go

License

FOSSA Status

This project is licensed under the MIT License - see the LICENSE file for details.

Disclaimer

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!

Related Projects

  • IceFireDB - A distributed database based on RedHub
  • gnet - High-performance event-loop networking framework

Documentation

Support

Acknowledgments

About

High-performance Redis-Server multi-threaded framework, based on rawepoll model.

Topics

Resources

Code of conduct

Contributing

Stars

80 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages