• Stars
    star
    137
  • Rank 256,738 (Top 6 %)
  • Language
    Go
  • License
    Creative Commons ...
  • Created 10 months ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

High-performance Redis library for Go

redjet

Go Reference ci Coverage Status Go Report Card

redjet is a high-performance Go library for Redis. Its hallmark feature is a low-allocation, streaming API. See the benchmarks section for more details.

Unlike redigo and go-redis, redjet does not provide a function for every Redis command. Instead, it offers a generic interface that supports all commands and options. While this approach has less type-safety, it provides forward compatibility with new Redis features.

In the aim of both performance and ease-of-use, redjet attempts to provide an API that closely resembles the protocol. For example, the Command method is really a Pipeline of size 1.

Table of Contents

Basic Usage

Install:

go get github.com/coder/redjet@latest

For the most part, you can interact with Redis using a familiar interface:

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/coder/redjet"
)

func main() {
    client := redjet.New("localhost:6379")
    ctx := context.Background()

    err := client.Command(ctx, "SET", "foo", "bar").Ok()
    // check error

    got, err := client.Command(ctx, "GET", "foo").Bytes()
    // check error
    // got == []byte("bar")
}

Streaming

To minimize allocations, call (*Pipeline).WriteTo instead of (*Pipeline).Bytes. WriteTo streams the response directly to an io.Writer such as a file or HTTP response.

For example:

_, err := client.Command(ctx, "GET", "big-object").WriteTo(os.Stdout)
// check error

Similarly, you can pass in a value that implements redjet.LenReader to Command to stream larger values into Redis. Unfortunately, the API cannot accept a regular io.Reader because bulk string messages in the Redis protocol are length-prefixed.

Here's an example of streaming a large file into Redis:

bigFile, err := os.Open("bigfile.txt")
// check error
defer bigFile.Close()

stat, err := bigFile.Stat()
// check error

err = client.Command(
    ctx, "SET", "bigfile",
    redjet.NewLenReader(bigFile, stat.Size()),
).Ok()
// check error

If you have no way of knowing the size of your blob in advance and still want to avoid large allocations, you may chunk a stream into Redis using repeated APPEND commands.

Pipelining

redjet supports pipelining via the (*Client).Pipeline method. This method accepts a Pipeline, potentially that of a previous, open command.

// Set foo0, foo1, ..., foo99 to "bar", and confirm that each succeeded.
//
// This entire example only takes one round-trip to Redis!
var p *Pipeline
for i := 0; i < 100; i++ {
    p = client.Pipeline(p, "SET", fmt.Sprintf("foo%d", i), "bar")
}

for r.Next() {
    if err := p.Ok(); err != nil {
        log.Fatal(err)
    }
}
p.Close() // allow the underlying connection to be reused.

PubSub

redjet suports PubSub via the NextSubMessage method. For example:

// Subscribe to a channel
sub := client.Command(ctx, "SUBSCRIBE", "my-channel")
sub.NextSubMessage() // ignore the first message, which is a confirmation of the subscription

// Publish a message to the channel
n, err := client.Command(ctx, "PUBLISH", "my-channel", "hello world").Int()
// check error
// n == 1, since there is one subscriber

// Receive the message
sub.NextSubMessage()
// sub.Payload == "hello world"
// sub.Channel == "my-channel"
// sub.Type == "message"

Note that NextSubMessage will block until a message is received. To interrupt the subscription, cancel the context passed to Command.

Once a connection enters subscribe mode, the internal pool does not re-use it.

It is possible to subscribe to a channel in a performant, low-allocation way via the public API. NextSubMessage is just a convenience method.

JSON

redjet supports convenient JSON encoding and decoding via the (*Pipeline).JSON method. For example:

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

// Set a person
// Unknown argument types are automatically encoded to JSON.
err := client.Command(ctx, "SET", "person", Person{
    Name: "Alice",
    Age:  30,
}).Ok()
// check error

// Get a person
var p Person
client.Command(ctx, "GET", "person").JSON(&p)
// check error

// p == Person{Name: "Alice", Age: 30}

Connection Pooling

Redjet provides automatic connection pooling. Configuration knobs exist within the Client struct that may be changed before any Commands are issued.

If you want synchronous command execution over the same connection, use the Pipeline method and consume the Pipeline after each call to Pipeline. Storing a long-lived Pipeline offers the same functionality as storing a long-lived connection.

Benchmarks

On a pure throughput basis, redjet will perform similarly to redigo and go-redis. But, since redjet doesn't allocate memory for the entire response object, it consumes far less resources when handling large responses.

Here are some benchmarks (reproducible via make gen-bench) to illustrate:

.fullname: Get/1_B-10
 β”‚   redjet    β”‚               redigo               β”‚           go-redis            β”‚               rueidis                β”‚
 β”‚   sec/op    β”‚   sec/op     vs base               β”‚   sec/op     vs base          β”‚    sec/op     vs base                β”‚
   908.2n Β± 2%   962.4n Β± 1%  +5.97% (p=0.000 n=10)   913.8n Β± 3%  ~ (p=0.280 n=10)   1045.0n Β± 1%  +15.06% (p=0.000 n=10)

 β”‚    redjet     β”‚                redigo                β”‚            go-redis             β”‚               rueidis                β”‚
 β”‚      B/s      β”‚      B/s       vs base               β”‚      B/s       vs base          β”‚     B/s       vs base                β”‚
   1074.2Ki Β± 2%   1015.6Ki Β± 1%  -5.45% (p=0.000 n=10)   1069.3Ki Β± 2%  ~ (p=0.413 n=10)   937.5Ki Β± 1%  -12.73% (p=0.000 n=10)

 β”‚  redjet   β”‚            redigo            β”‚           go-redis            β”‚            rueidis            β”‚
 β”‚   B/op    β”‚    B/op     vs base          β”‚    B/op      vs base          β”‚    B/op      vs base          β”‚
   0.00 Β± 0%   41.00 Β± 0%  ? (p=0.000 n=10)   275.50 Β± 2%  ? (p=0.000 n=10)   249.00 Β± 0%  ? (p=0.000 n=10)

 β”‚   redjet   β”‚            redigo            β”‚           go-redis           β”‚           rueidis            β”‚
 β”‚ allocs/op  β”‚ allocs/op   vs base          β”‚ allocs/op   vs base          β”‚ allocs/op   vs base          β”‚
   0.000 Β± 0%   3.000 Β± 0%  ? (p=0.000 n=10)   4.000 Β± 0%  ? (p=0.000 n=10)   2.000 Β± 0%  ? (p=0.000 n=10)

.fullname: Get/1.0_kB-10
 β”‚   redjet    β”‚               redigo                β”‚              go-redis               β”‚               rueidis               β”‚
 β”‚   sec/op    β”‚   sec/op     vs base                β”‚   sec/op     vs base                β”‚   sec/op     vs base                β”‚
   1.302Β΅ Β± 2%   1.802Β΅ Β± 1%  +38.42% (p=0.000 n=10)   1.713Β΅ Β± 3%  +31.58% (p=0.000 n=10)   1.645Β΅ Β± 1%  +26.35% (p=0.000 n=10)

 β”‚    redjet    β”‚                redigo                β”‚               go-redis               β”‚               rueidis                β”‚
 β”‚     B/s      β”‚     B/s       vs base                β”‚     B/s       vs base                β”‚     B/s       vs base                β”‚
   750.4Mi Β± 2%   542.1Mi Β± 1%  -27.76% (p=0.000 n=10)   570.3Mi Β± 3%  -24.01% (p=0.000 n=10)   593.8Mi Β± 1%  -20.87% (p=0.000 n=10)

 β”‚    redjet    β”‚             redigo             β”‚            go-redis            β”‚            rueidis             β”‚
 β”‚     B/op     β”‚     B/op      vs base          β”‚     B/op      vs base          β”‚     B/op      vs base          β”‚
   0.000Ki Β± 0%   1.039Ki Β± 0%  ? (p=0.000 n=10)   1.392Ki Β± 0%  ? (p=0.000 n=10)   1.248Ki Β± 1%  ? (p=0.000 n=10)

 β”‚   redjet   β”‚            redigo            β”‚           go-redis           β”‚           rueidis            β”‚
 β”‚ allocs/op  β”‚ allocs/op   vs base          β”‚ allocs/op   vs base          β”‚ allocs/op   vs base          β”‚
   0.000 Β± 0%   3.000 Β± 0%  ? (p=0.000 n=10)   4.000 Β± 0%  ? (p=0.000 n=10)   2.000 Β± 0%  ? (p=0.000 n=10)

.fullname: Get/1.0_MB-10
 β”‚   redjet    β”‚            redigo             β”‚              go-redis               β”‚            rueidis            β”‚
 β”‚   sec/op    β”‚   sec/op     vs base          β”‚   sec/op     vs base                β”‚   sec/op     vs base          β”‚
   472.5Β΅ Β± 7%   477.3Β΅ Β± 2%  ~ (p=0.190 n=10)   536.8Β΅ Β± 6%  +13.61% (p=0.000 n=10)   475.3Β΅ Β± 6%  ~ (p=0.684 n=10)

 β”‚    redjet    β”‚             redigo             β”‚               go-redis               β”‚            rueidis             β”‚
 β”‚     B/s      β”‚     B/s       vs base          β”‚     B/s       vs base                β”‚     B/s       vs base          β”‚
   2.067Gi Β± 8%   2.046Gi Β± 2%  ~ (p=0.190 n=10)   1.819Gi Β± 6%  -11.98% (p=0.000 n=10)   2.055Gi Β± 6%  ~ (p=0.684 n=10)

 β”‚   redjet    β”‚                    redigo                    β”‚                   go-redis                   β”‚                   rueidis                    β”‚
 β”‚    B/op     β”‚      B/op        vs base                     β”‚      B/op        vs base                     β”‚      B/op        vs base                     β”‚
   51.00 Β± 12%   1047849.50 Β± 0%  +2054506.86% (p=0.000 n=10)   1057005.00 Β± 0%  +2072458.82% (p=0.000 n=10)   1048808.50 Β± 0%  +2056387.25% (p=0.000 n=10)

 β”‚   redjet   β”‚               redigo                β”‚              go-redis               β”‚               rueidis               β”‚
 β”‚ allocs/op  β”‚ allocs/op   vs base                 β”‚ allocs/op   vs base                 β”‚ allocs/op   vs base                 β”‚
   1.000 Β± 0%   3.000 Β± 0%  +200.00% (p=0.000 n=10)   4.000 Β± 0%  +300.00% (p=0.000 n=10)   2.000 Β± 0%  +100.00% (p=0.000 n=10)

Limitations

  • redjet does not have convenient support for client side caching. But, the redjet API is flexible enough that a client could implement it themselves by following the instructions here.
  • RESP3 is not supported. Practically, this means that connections aren't multiplexed, and other Redis libraries may perform better in high-concurrency scenarios.
  • Certain features have not been tested but may still work:
    • Redis Streams
    • Monitor

More Repositories

1

code-server

VS Code in the browser
TypeScript
65,191
star
2

coder

Provision remote development environments via Terraform
Go
6,912
star
3

sshcode

Run VS Code on any server over SSH.
Go
5,741
star
4

deploy-code-server

Deploy code-server to the cloud with a few clicks ☁️ πŸ‘¨πŸΌβ€πŸ’»
Shell
834
star
5

sail

Deprecated: Instant, pre-configured VS Code development environments.
Go
630
star
6

slog

Minimal structured logging library for Go
Go
328
star
7

code-marketplace

Open source extension marketplace for VS Code.
Go
186
star
8

awesome-code-server

Projects, resources, and tutorials that take code-server to the next level
154
star
9

awesome-coder

A curated list of awesome Coder resources.
113
star
10

nbin

Fast and robust node.js binary compiler.
TypeScript
106
star
11

enterprise-images

Example Docker images for use with Coder
Shell
88
star
12

envbuilder

Build development environments from a Dockerfile on Docker, Kubernetes, and OpenShift. Enable developers to modify their development environment quickly.
Go
83
star
13

coder-v1-cli

Command line for Coder v1. For Coder v2, go to https://github.com/coder/coder
72
star
14

cli

A minimal Go CLI package.
Go
48
star
15

enterprise-helm

Operate Coder v1 on Kubernetes
Go
44
star
16

vscode-coder

Open any Coder workspace in VS Code with a single click.
TypeScript
41
star
17

retry

A tiny retry package for Go.
Go
38
star
18

hat

HTTP API testing for Go
Go
36
star
19

wgtunnel

HTTP tunnels over Wireguard
Go
33
star
20

envbox

envbox is an image that enables creating non-privileged containers capable of running system-level software (e.g. dockerd, systemd, etc) in Kubernetes.
Go
27
star
21

node-browser

Use Node in the browser.
TypeScript
26
star
22

wsep

High performance command execution protocol
Go
24
star
23

terraform-provider-coder

Go
23
star
24

flog

Pretty formatted log for Go
Go
22
star
25

packages

Deploy Coder to your preferred cloud with a pre-built package.
HCL
22
star
26

backstage-plugins

Official Coder plugins for the Backstage platform
TypeScript
22
star
27

docs

Markdown content for Coder v1 Docs.
Shell
20
star
28

modules

A collection of Terraform Modules to work with Coder.
HCL
20
star
29

exectrace

Simple eBPF-based exec snooping on Linux packaged as a Go library.
Go
19
star
30

jetbrains-coder

A JetBrains Plugin for Coder Workspaces
Kotlin
17
star
31

code-server-aur

code-server AUR package
Shell
15
star
32

requirefs

Create a readable and requirable file system from tars, zips, or a custom provider.
TypeScript
11
star
33

labeler

A GitHub app that labels your issues for you
Go
10
star
34

cloud-agent

The agent for Coder Cloud
Go
10
star
35

ts-logger

TypeScript
10
star
36

coder.rs

[EXPERIMENTAL] Asynchronous Rust wrapper around the Coder Enterprise API
Rust
9
star
37

coder-logstream-kube

Stream Kubernetes Pod events to the Coder startup logs
Go
9
star
38

pretty

TTY styles for Go
Go
9
star
39

homebrew-coder

Coder Homebrew Tap
Ruby
8
star
40

bigdur

A Go package for parsing larger durations.
Go
8
star
41

timer

Accurately measure how long a command takes to run
Go
7
star
42

serpent

CLI framework for scale and configurability inspired by Cobra
Go
5
star
43

coder-doctor

A preflight check tool for Coder
Go
5
star
44

blogs

Content for coder.com/blog
D2
5
star
45

webinars

HCL
4
star
46

nfy

EXPERIMENTAL: Pumped up install scripts
Go
4
star
47

ghlabels

A tool to synchronize labels on GitHub repositories sanely.
Go
4
star
48

devcontainer-webinar

The Good, The Bad, And The Future of Dev Containers
Shell
4
star
49

envbuilder-starter-devcontainer

A sample project for getting started with devcontainer.json in envbuilder
Dockerfile
4
star
50

presskit

press kit and brand assets for Coder.com
3
star
51

gke-disk-cleanup

Go
3
star
52

cla

The Coder Contributor License Agreement (CLA)
3
star
53

styleguide

2
star
54

codercord

A Discord bot for our community server
Dart
2
star
55

support-scripts

Things for Coder Customer Success.
Shell
2
star
56

enterprise-terraform

Terraform modules and examples for deploying Coder
HCL
2
star
57

sail-aur

sail AUR package
Shell
2
star
58

grip

extensible logging and messaging framework for go processes.
Go
1
star
59

coder-xray

JFrog XRay Integration
Go
1
star
60

presentations

Talks and presentations related to Coder released under CC0 which permits remixing and reuse!
1
star
61

.github

1
star
62

community-templates

Unofficial templates for Coder for various platforms and cloud providers
HCL
1
star
63

coder-docs-generator

Generates off-line docs for Coder Docs
TypeScript
1
star
64

gott

go test timer
Go
1
star
65

wxnm

A library for providing TypeScript typed communication between your web extension and your native Node application using Native Messaging
TypeScript
1
star
66

jetbrains-backend-coder

Kotlin
1
star