• Stars
    star
    579
  • Rank 74,153 (Top 2 %)
  • Language
    Go
  • License
    MIT License
  • Created about 5 years ago
  • Updated about 1 year ago

Reviews

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

Repository Details

High Availability Raft Framework for Go

uhaha

GoDoc

High Availabilty Framework for Happy Data

Uhaha is a framework for building highly available Raft-based data applications in Go. This is basically an upgrade to the Finn project, but has an updated API, better security features (TLS and auth passwords), customizable services, deterministic time, recalculable random numbers, simpler snapshots, a smaller network footprint, and more. Under the hood it utilizes hashicorp/raft, tidwall/redcon, and syndtr/goleveldb.

Features

  • Simple API for quickly creating a custom Raft-based application.
  • Deterministic monotonic time that does not drift and stays in sync with the internet.
  • APIs for building custom services such as HTTP and gRPC. Supports the Redis protocol by default, so most Redis client library will work with Uhaha.
  • TLS and Auth password support.
  • Multiple examples to help jumpstart integration, including a Key-value DB, a Timeseries DB, and a Ticket Service.

Example

Below a simple example of a service for monotonically increasing tickets.

package main

import "github.com/tidwall/uhaha"

type data struct {
	Ticket int64
}

func main() {
	// Set up a uhaha configuration
	var conf uhaha.Config
	
	// Give the application a name. All servers in the cluster should use the
	// same name.
	conf.Name = "ticket"
	
	// Set the initial data. This is state of the data when first server in the 
	// cluster starts for the first time ever.
	conf.InitialData = new(data)

	// Since we are not holding onto much data we can used the built-in JSON
	// snapshot system. You just need to make sure all the important fields in
	// the data are exportable (capitalized) to JSON. In this case there is
	// only the one field "Ticket".
	conf.UseJSONSnapshots = true
	
	// Add a command that will change the value of a Ticket. 
	conf.AddWriteCommand("ticket", cmdTICKET)

	// Finally, hand off all processing to uhaha.
	uhaha.Main(conf)
}

// TICKET
// help: returns a new ticket that has a value that is at least one greater
// than the previous TICKET call.
func cmdTICKET(m uhaha.Machine, args []string) (interface{}, error) {
	// The the current data from the machine
	data := m.Data().(*data)

	// Increment the ticket
	data.Ticket++

	// Return the new ticket to caller
	return data.Ticket, nil
}

Building

Using the source file from the examples directory, we'll build an application named "ticket"

go build -o ticket examples/ticket/main.go

Running

It's ideal to have three, five, or seven nodes in your cluster.

Let's create the first node.

./ticket -n 1 -a :11001

This will create a node named 1 and bind the address to :11001

Now let's create two more nodes and add them to the cluster.

./ticket -n 2 -a :11002 -j :11001
./ticket -n 3 -a :11003 -j :11001

Now we have a fault-tolerant three node cluster up and running.

Using

You can use any Redis compatible client, such as the redis-cli, telnet, or netcat.

I'll use the redis-cli in the example below.

Connect to the leader. This will probably be the first node you created.

redis-cli -p 11001

Send the server a TICKET command and receive the first ticket.

> TICKET
"1"

From here on every TICKET command will guarentee to generate a value larger than the previous TICKET command.

> TICKET
"2"
> TICKET
"3"
> TICKET
"4"
> TICKET
"5"

Built-in Commands

There are a number built-in commands for managing and monitor the cluster.

VERSION                                 # show the application version
MACHINE                                 # show information about the state machine
RAFT LEADER                             # show the address of the current raft leader
RAFT INFO [pattern]                     # show information about the raft server and cluster
RAFT SERVER LIST                        # show all servers in cluster
RAFT SERVER ADD id address              # add a server to cluster
RAFT SERVER REMOVE id                   # remove a server from the cluster
RAFT SNAPSHOT NOW                       # make a snapshot of the data
RAFT SNAPSHOT LIST                      # show a list of all snapshots on server
RAFT SNAPSHOT FILE id                   # show the file path of a snapshot on server
RAFT SNAPSHOT READ id [RANGE start end] # download all or part of a snapshot

And also some client commands.

QUIT                                    # close the client connection
PING                                    # ping the server
ECHO [message]                          # echo a message to the server
AUTH password                           # authenticate with a password

Network and security considerations (TLS and Auth password)

By default a single Uhaha instance is bound to the local 127.0.0.1 IP address. Thus nothing outside that machine, including other servers in the cluster or machines on the same local network will be able communicate with this instance.

Network security

To open up the service you will need to provide an IP address that can be reached from the outside. For example, let's say you want to set up three servers on a local 10.0.0.0 network.

On server 1:

./ticket -n 1 -a 10.0.0.1:11001

On server 2:

./ticket -n 2 -a 10.0.0.2:11001 -j 10.0.0.1:11001

On server 3:

./ticket -n 3 -a 10.0.0.3:11001 -j 10.0.0.1:11001

Now you have a Raft cluster running on three distinct servers in the same local network. This may be enough for applications that only require a network security policy. Basically any server on the local network can access the cluster.

Auth password

If you want to lock down the cluster further you can provide a secret auth, which is more or less a password that the cluster and client will need to communicate with each other.

./ticket -n 1 -a 10.0.0.1:11001 --auth my-secret

All the servers will need to be started with the same auth.

./ticket -n 2 -a 10.0.0.2:11001 --auth my-secret -j 10.0.0.1:11001
./ticket -n 2 -a 10.0.0.3:11001 --auth my-secret -j 10.0.0.1:11001

The client will also need the same auth to talk with cluster. All redis clients support an auth password, such as:

redis-cli -h 10.0.0.1 -p 11001 -a my-secret

This may be enough if you keep all your machines on the same private network, but you don't want all machines or applications to have unfettered access to the cluster.

TLS

Finally you can use TLS, which I recommend along with an auth password.

In this example a custom cert and key are created using the mkcert tool.

mkcert uhaha-example
# produces uhaha-example.pem, uhaha-example-key.pem, and a rootCA.pem

Then create a cluster using the cert & key files. Along with an auth.

./ticket -n 1 -a 10.0.0.1:11001 --tls-cert uhaha-example.pem --tls-key uhaha-example-key.pem --auth my-secret
./ticket -n 2 -a 10.0.0.2:11001 --tls-cert uhaha-example.pem --tls-key uhaha-example-key.pem --auth my-secret -j 10.0.0.1:11001
./ticket -n 2 -a 10.0.0.3:11001 --tls-cert uhaha-example.pem --tls-key uhaha-example-key.pem --auth my-secret -j 10.0.0.1:11001

Now you can connect to the server from a client that has the rootCA.pem. You can find the location of your rootCA.pem file in the running ls "$(mkcert -CAROOT)/rootCA.pem".

redis-cli -h 10.0.0.1 -p 11001 --tls --cacert rootCA.pem -a my-secret

Command-line options

Below are all of the command line options.

Usage: my-uhaha-app [-n id] [-a addr] [options]

Basic options:
  -v               : display version
  -h               : display help, this screen
  -a addr          : bind to address  (default: 127.0.0.1:11001)
  -n id            : node ID  (default: 1)
  -d dir           : data directory  (default: data)
  -j addr          : leader address of a cluster to join
  -l level         : log level  (default: info) [debug,verb,info,warn,silent]

Security options:
  --tls-cert path  : path to TLS certificate
  --tls-key path   : path to TLS private key
  --auth auth      : cluster authorization, shared by all servers and clients

Networking options:
  --advertise addr : advertise address  (default: network bound address)

Advanced options:
  --nosync         : turn off syncing data to disk after every write. This leads
                     to faster write operations but opens up the chance for data
                     loss due to catastrophic events such as power failure.
  --openreads      : allow followers to process read commands, but with the
                     possibility of returning stale data.
  --localtime      : have the raft machine time synchronized with the local
                     server rather than the public internet. This will run the
                     risk of time shifts when the local server time is
                     drastically changed during live operation.
  --restore path   : restore a raft machine from a snapshot file. This will
                     start a brand new single-node cluster using the snapshot as
                     initial data. The other nodes must be re-joined. This
                     operation is ignored when a data directory already exists.
                     Cannot be used with -j flag.

More Repositories

1

gjson

Get JSON values quickly - JSON parser for Go
Go
12,768
star
2

tile38

Real-time Geospatial and Geofencing
Go
8,655
star
3

evio

Fast event-loop networking for Go
Go
5,747
star
4

buntdb

BuntDB is an embeddable, in-memory key/value database for Go with custom indexing and geospatial support
Go
4,196
star
5

redcon

Redis compatible server framework for Go
Go
2,005
star
6

sjson

Set JSON values very quickly in Go
Go
1,978
star
7

SwiftWebSocket

Fast Websockets in Swift for iOS and OSX
Swift
1,532
star
8

summitdb

In-memory NoSQL database with ACID transactions, Raft consensus, and Redis API
Go
1,394
star
9

jj

JSON Stream Editor (command line utility)
Go
1,293
star
10

btree

B-tree implementation for Go
Go
937
star
11

hashmap.c

Hash map implementation in C.
C
631
star
12

pinhole

3D Wireframe Drawing Library for Go
Go
554
star
13

finn

Fast Raft framework using the Redis protocol for Go
Go
541
star
14

wal

Write ahead log for Go.
Go
525
star
15

tg

Geometry library for C - Fast point-in-polygon
C
502
star
16

Safe

Modern Concurrency and Synchronization for Swift.
Swift
417
star
17

pretty

Efficient JSON beautifier and compactor for Go
Go
354
star
18

chanx

A simple interface wrapper around a Go channel.
Go
321
star
19

rtree

An R-tree implementation for Go
Go
285
star
20

btree.c

B-tree implementation in C
C
246
star
21

GoSwift

Go Goodies for Swift. Including goroutines, channels, defer, and panic.
Swift
234
star
22

shardmap

A simple and efficient thread-safe sharded hashmap for Go
Go
211
star
23

hashmap

A simple and efficient hashmap package for Go. Open addressing, robin hood hashing, and xxh3 algorithm. Supports generics.
Go
203
star
24

celltree

A fast in-memory prefix tree that uses uint64 for keys and allows for duplicate entries.
Go
201
star
25

gjson.rs

Get JSON values quickly - JSON parser for Rust
Rust
195
star
26

cities

10,000 Cities with Latitude, Longitude, and Elevation in Go
Go
161
star
27

tinylru

A fast little LRU cache for Go
Go
144
star
28

Avios

Realtime H264 decoding library for iOS.
Swift
129
star
29

jd

Interactive JSON Editor
Go
128
star
30

pinhole-js

3D Wireframe Drawing Library for HTML Canvas
JavaScript
119
star
31

mmap

Load file-backed memory
Go
117
star
32

geojson

GeoJSON for Go. Used by Tile38
Go
116
star
33

doppio

Doppio is a fast LRU cache on top of Ristretto, Redcon, and Evio. Support for the Redis protocol.
Go
115
star
34

rtree.rs

A fast R-tree for Rust
Rust
112
star
35

match

Simple string pattern matcher for Go
Go
97
star
36

rtree.c

An R-tree implementation in C
C
96
star
37

tinybtree

Just an itsy bitsy b-tree in Go
Go
94
star
38

jsonc

Parse json with comments and trailing commas.
Go
79
star
39

rhh

A simple and efficient hashmap package for Go. Uses open addressing, Robin Hood hashing, and xxhash algorithm.
Go
79
star
40

kvnode

key value server. redis api, leveldb storage, raft support
Go
79
star
41

raft-fastlog

Raft in-memory backend implementation with persistence
Go
78
star
42

resp

Reader, Writer, and Server implementation for the Redis RESP Protocol.
Go
78
star
43

modern-server

Basic web server framework with HTTP/2 and Let's Encrypt.
Go
76
star
44

limiter

A goroutine limiter for Go
Go
76
star
45

redraft

Redis + Raft server implementation
Go
75
star
46

redcon.rs

Redis compatible server framework for Rust
Rust
72
star
47

rocksdb-server

Fast Redis clone written in C using RocksDB as a backend.
C++
72
star
48

lotsa

Simple Go library for executing lots of operations spread over any number of threads
Go
71
star
49

box

Efficiently box values in Go. Optimized for primitives, strings, and byte slices.
Go
69
star
50

evio-lite

Fast event-loop networking for Go (the lite version)
Go
68
star
51

transform

Using io.Reader for data transformation in Go
Go
67
star
52

uspto-trademark

How to file a USPTO trademark without an attorney for $225
66
star
53

pjson

A JSON stream parser for Go
Go
66
star
54

geodesic

Go package for performing accurate measurements of Earth. Includes the geodesic routines from GeographicLib.
Go
59
star
55

expr

Expression evaluator for Go
Go
58
star
56

json.c

Fast JSON parser for C
C
56
star
57

spinlock

A spinlock implementation for Go.
Go
56
star
58

raft-wal

Write ahead Raft log for Go
Go
55
star
59

rtred

RTree implementation for Go
Go
53
star
60

bfile

A buffer pool file I/O library for Go
Go
53
star
61

mvt

Draw Mapbox Vector Tiles (MVT) in Go
Go
52
star
62

redcon.c

Redis compatible server framework for C
C
47
star
63

cache-server

A minimal key/value server written in Rust with Redis API support.
Rust
46
star
64

spanmap

A fast collection type that uses uint64 for keys.
Go
44
star
65

go-node

Run Javascript in Go using Node.js
Go
42
star
66

ticketd

A distributed service for monotonically increasing tickets.
Go
42
star
67

hexd

Please love the nicely formatted hex.
Go
42
star
68

DeflateSwift

Deflate Compression for Swift
Swift
40
star
69

proximity-chat

Chat app for real-time chats with people within 500 meters.
JavaScript
39
star
70

lru

A simple and efficient LRU cache package for Go
Go
38
star
71

sider

A Redis clone written in Go
Go
36
star
72

xv

An expression evaluator for C
C
34
star
73

geometry

Efficient 2D geometry library for Go.
Go
32
star
74

pkg.sh

A generalized package manager for whatever code.
Shell
32
star
75

rfront

An HTTP protocol frontend for Redis-compatible services.
Go
31
star
76

redis-gis

Redis fork with Geospatial support based on Tile38 commands
C
31
star
77

RetroSwiper

Load classic games from magnetic swipe cards
Rust
31
star
78

uhasql

A high availability Sqlite service
C
30
star
79

redbench

Benchmarking for custom Redis commands and modules
Go
30
star
80

sds

simple data streams for go
Go
29
star
81

spmap

A hashmap for Go that uses crypto random seeds, hash hints, open addressing, and robin hood hashing.
Go
29
star
82

IoniconsSwift

Ionicons for Swift and iOS
Swift
29
star
83

evio.c

A framework for building event based networking applications.
C
28
star
84

raft-leveldb

Raft backend using LevelDB
Go
28
star
85

tinyqueue

Binary heap priority queues in Go
Go
27
star
86

kvbench

Server for benchmarking pure Go key/value databases
Go
26
star
87

gjson-play

A playground for GJSON. Runs in the browser.
JavaScript
25
star
88

randjson

Make random JSON in Go
Go
25
star
89

redlog

Redis style logger for Go
Go
25
star
90

SnapHTTP

An incredibly simple HTTP client library for Swift.
Swift
24
star
91

qtree

jeez it's just a quadtree chill out
Go
24
star
92

rtime

Retrieve the current time from remote servers
Go
21
star
93

fast-spatial-joins

Go vs GPU: Fast Spatial Joins
Go
21
star
94

assert

An assert function for Go that works like the one in C.
Go
20
star
95

pair

create low memory key/value objects in Go
Go
20
star
96

match.c

Simple string pattern matcher for C
C
19
star
97

secret

A simple utility for encrypting and decrypting data in Go (AES-256-CFB)
Go
19
star
98

pony

🌈 🐴 Turn your terminal text into an absolutely beautiful display of dazzling colors....
Go
19
star
99

btree-benchmark

Benchmark utility for the tidwall/btree Go package
Go
19
star
100

lru-server

A convenient LRU cache server that supports REST API and Let's Encrypt.
Go
18
star