package
0.0.0-20240819164739-f47aed85de5a
Repository: https://github.com/unix-world/smartgo.git
Documentation: pkg.go.dev

# README

REDCON
GoDoc

Redis compatible server framework for Go

Features

  • Create a Fast custom Redis compatible server in Go
  • Simple interface. One function ListenAndServe and two types Conn & Command
  • Support for pipelining and telnet commands
  • Works with Redis clients such as redigo, redis-py, node_redis, and jedis
  • TLS Support
  • Compatible pub/sub support
  • Multithreaded

This library is also avaliable for Rust and C.

Installing

go get -u github.com/tidwall/redcon

Example

Here's a full example of a Redis clone that accepts:

  • SET key value
  • GET key
  • DEL key
  • PING
  • QUIT
  • PUBLISH channel message
  • SUBSCRIBE channel

You can run this example from a terminal:

go run example/clone.go
package main

import (
	"log"
	"strings"
	"sync"

	"github.com/tidwall/redcon"
)

var addr = ":6380"

func main() {
	var mu sync.RWMutex
	var items = make(map[string][]byte)
	var ps redcon.PubSub
	go log.Printf("started server at %s", addr)
	err := redcon.ListenAndServe(addr,
		func(conn redcon.Conn, cmd redcon.Command) {
			switch strings.ToLower(string(cmd.Args[0])) {
			default:
				conn.WriteError("ERR unknown command '" + string(cmd.Args[0]) + "'")
			case "ping":
				conn.WriteString("PONG")
			case "quit":
				conn.WriteString("OK")
				conn.Close()
			case "set":
				if len(cmd.Args) != 3 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				mu.Lock()
				items[string(cmd.Args[1])] = cmd.Args[2]
				mu.Unlock()
				conn.WriteString("OK")
			case "get":
				if len(cmd.Args) != 2 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				mu.RLock()
				val, ok := items[string(cmd.Args[1])]
				mu.RUnlock()
				if !ok {
					conn.WriteNull()
				} else {
					conn.WriteBulk(val)
				}
			case "del":
				if len(cmd.Args) != 2 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				mu.Lock()
				_, ok := items[string(cmd.Args[1])]
				delete(items, string(cmd.Args[1]))
				mu.Unlock()
				if !ok {
					conn.WriteInt(0)
				} else {
					conn.WriteInt(1)
				}
			case "publish":
				if len(cmd.Args) != 3 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				conn.WriteInt(ps.Publish(string(cmd.Args[1]), string(cmd.Args[2])))
			case "subscribe", "psubscribe":
				if len(cmd.Args) < 2 {
					conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
					return
				}
				command := strings.ToLower(string(cmd.Args[0]))
				for i := 1; i < len(cmd.Args); i++ {
					if command == "psubscribe" {
						ps.Psubscribe(conn, string(cmd.Args[i]))
					} else {
						ps.Subscribe(conn, string(cmd.Args[i]))
					}
				}
			}
		},
		func(conn redcon.Conn) bool {
			// Use this function to accept or deny the connection.
			// log.Printf("accept: %s", conn.RemoteAddr())
			return true
		},
		func(conn redcon.Conn, err error) {
			// This is called when the connection has been closed
			// log.Printf("closed: %s, err: %v", conn.RemoteAddr(), err)
		},
	)
	if err != nil {
		log.Fatal(err)
	}
}

TLS Example

Redcon has full TLS support through the ListenAndServeTLS function.

The same example is also provided for serving Redcon over TLS.

go run example/tls/clone.go

Benchmarks

Redis: Single-threaded, no disk persistence.

$ redis-server --port 6379 --appendonly no
redis-benchmark -p 6379 -t set,get -n 10000000 -q -P 512 -c 512
SET: 941265.12 requests per second
GET: 1189909.50 requests per second

Redcon: Single-threaded, no disk persistence.

$ GOMAXPROCS=1 go run example/clone.go
redis-benchmark -p 6380 -t set,get -n 10000000 -q -P 512 -c 512
SET: 2018570.88 requests per second
GET: 2403846.25 requests per second

Redcon: Multi-threaded, no disk persistence.

$ GOMAXPROCS=0 go run example/clone.go
$ redis-benchmark -p 6380 -t set,get -n 10000000 -q -P 512 -c 512
SET: 1944390.38 requests per second
GET: 3993610.25 requests per second

Running on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7

Contact

Josh Baker @tidwall

License

Redcon source code is available under the MIT License.

# Packages

No description provided by the author

# Functions

AppendAny appends any type to valid Redis type.
AppendArray appends a Redis protocol array to the input bytes.
AppendBulk appends a Redis protocol bulk byte slice to the input bytes.
AppendBulkFloat appends a float64, as bulk bytes.
AppendBulkInt appends an int64, as bulk bytes.
AppendBulkString appends a Redis protocol bulk string to the input bytes.
AppendBulkUint appends an uint64, as bulk bytes.
AppendError appends a Redis protocol error to the input bytes.
AppendInt appends a Redis protocol int64 to the input bytes.
AppendNull appends a Redis protocol null to the input bytes.
AppendOK appends a Redis protocol OK to the input bytes.
AppendString appends a Redis protocol string to the input bytes.
AppendTile38 appends a Tile38 message to the input bytes.
AppendUint appends a Redis protocol uint64 to the input bytes.
BaseWriter returns the underlying connection writer, if any.
ListenAndServe creates a new server and binds to addr configured on "tcp" network net.
ListenAndServeNetwork creates a new server and binds to addr.
ListenAndServeNetworkTLS creates a new TLS server and binds to addr.
ListenAndServeTLS creates a new TLS server and binds to addr configured on "tcp" network net.
NewReader returns a command reader which will read RESP or telnet commands.
NewServeMux allocates and returns a new ServeMux.
NewServer returns a new Redcon server configured on "tcp" network net.
NewServerNetwork returns a new Redcon server.
NewServerNetworkTLS returns a new TLS Redcon server.
NewServerTLS returns a new Redcon TLS server configured on "tcp" network net.
NewWriter creates a new RESP writer.
Parse parses a raw RESP message and returns a command.
ReadNextCommand reads the next command from the provided packet.
ReadNextRESP returns the next resp in b and returns the number of bytes the took up the result.
Serve creates a new server and serves with the given net.Listener.

# Constants

Various RESP kinds.
Various RESP kinds.
Various RESP kinds.
Various RESP kinds.
Redis is returned for Redis protocol commands.
Various RESP kinds.
Telnet is returnd for plain telnet commands.
Tile38 is returnd for Tile38 native protocol commands.

# Structs

Command represent a command.
PubSub is a Redis compatible pub/sub server.
Reader represent a reader for RESP or telnet commands.
No description provided by the author
ServeMux is an RESP command multiplexer.
Server defines a server for clients for managing client connections.
TLSServer defines a server for clients for managing client connections.
Writer allows for writing RESP messages.

# Interfaces

Conn represents a client connection.
DetachedConn represents a connection that is detached from the server.
A Handler responds to an RESP request.
Marshaler is the interface implemented by types that can marshal themselves into a Redis response type from an *Any call.

# Type aliases

The HandlerFunc type is an adapter to allow the use of ordinary functions as RESP handlers.
Kind is the kind of command.
SimpleError is for representing an error without adding the "ERR" prefix from an *Any call.
SimpleInt is for representing a non-bulk representation of a int from an *Any call.
SimpleString is for representing a non-bulk representation of a string from an *Any call.
Type of RESP.