Skip to content

Commit

Permalink
Create benchmark comparison script against Redis (#143)
Browse files Browse the repository at this point in the history
* Create benchmark comparison script against Redis - @NicoleStrel
  • Loading branch information
NicoleStrel authored Nov 1, 2024
1 parent c7f492f commit 974ba1b
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 26 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ test-win:
cover:
go tool cover -html=./coverage/coverage.out

benchmark:
go run redis_benchmark.go $(if $(commands),-commands="$(commands)") $(if $(use_local_server),-use_local_server)
34 changes: 10 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,31 +155,17 @@ Redis clients.

<a name="benchmarks"></a>
# Benchmarks
The following benchmark only applies to the TCP client-server mode.
To compare command performance with Redis, benchmarks can be run with:

Hardware: MacBook Pro 14in, M1 chip, 16GB RAM, 8 Cores <br/>
Command: `redis-benchmark -h localhost -p 7480 -q -t ping,set,get,incr,lpush,rpush,lpop,rpop,sadd,hset,zpopmin,lrange,mset` <br/>
Result:
```
PING_INLINE: 89285.71 requests per second, p50=0.247 msec
PING_MBULK: 85543.20 requests per second, p50=0.239 msec
SET: 65573.77 requests per second, p50=0.455 msec
GET: 79176.56 requests per second, p50=0.295 msec
INCR: 68870.52 requests per second, p50=0.439 msec
LPUSH: 27601.44 requests per second, p50=1.567 msec
RPUSH: 61842.92 requests per second, p50=0.519 msec
LPOP: 58548.01 requests per second, p50=0.567 msec
RPOP: 68681.32 requests per second, p50=0.439 msec
SADD: 67613.25 requests per second, p50=0.479 msec
HSET: 56561.09 requests per second, p50=0.599 msec
ZPOPMIN: 70972.32 requests per second, p50=0.359 msec
LPUSH (needed to benchmark LRANGE): 26434.05 requests per second, p50=1.623 msec
LRANGE_100 (first 100 elements): 26939.66 requests per second, p50=1.263 msec
LRANGE_300 (first 300 elements): 5081.82 requests per second, p50=9.095 msec
LRANGE_500 (first 500 elements): 2554.87 requests per second, p50=18.191 msec
LRANGE_600 (first 600 elements): 1903.96 requests per second, p50=24.607 msec
MSET (10 keys): 56022.41 requests per second, p50=0.463 msec
```
`make benchmark`

Prerequisites:
- `brew install redis` to run the Redis server and benchmark script
- `brew tap echovault/sugardb` & `brew install echovault/echovault/sugardb` to run the SugarDB Client-Server

Benchmark script options:
- `make benchmark use_local_server=true` runs on your local SugarDB Client-Server
- `make benchmark commands=ping,set,get...` runs the benchmark script on the specified commands

<a name="commands"></a>
# Supported Commands
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ if err != nil {
### Homebrew

To install via homebrew, run:
1) `brew tap echovault/echovault`
2) `brew install echovault/echovault/echovault`
1) `brew tap echovault/sugardb`
2) `brew install echovault/echovault/sugardb`

Once installed, you can run the server with the following command:
`echovault --bind-addr=localhost --data-dir="path/to/persistence/directory"`
Expand Down
141 changes: 141 additions & 0 deletions redis_benchmark.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package main

import (
"flag"
"fmt"
"os"
"os/exec"
"strings"
"text/tabwriter"
"time"
)

const (
Host = "localhost"
SugarDBPort = "7480"
RedisPort = "6379"
)

type Metrics struct {
CommandName string
RequestsPerSecond string
P50Latency string
}

func getCommandArgs() (string, bool) {
defaultCommands := "ping,set,get,incr,lpush,rpush,lpop,rpop,sadd,hset,zpopmin,lrange,mset"
commands := flag.String("commands", defaultCommands, "Commands to run")
useLocal := flag.Bool("use_local_server", false, "Run benchamark using local SugarDB server")
flag.Parse()
fmt.Printf("Provided commands: %s\n", *commands)
if *useLocal {
fmt.Println("Using local running SugarDB server")
}
return *commands, *useLocal
}

func runBenchmark(port string, commands string) ([]Metrics, error) {
var results []Metrics

// Run redis-benchmark
cmd := exec.Command("redis-benchmark", "-h", Host, "-p", port, "-q", "-t", commands)
output, err := cmd.CombinedOutput()
if err != nil {
return nil, err
}

strOutput := string(output)
fmt.Println(strOutput)
lines := strings.Split(strOutput, "\n")
for _, line := range lines {
if !strings.HasPrefix(line, "WARNING") && line != "" {
// Get command name
colonIndex := strings.Index(line, ":")
commandName := line[:colonIndex]

// Get requests per second
reqSecIndex := strings.Index(line, " requests per second")
spaceIndex := strings.LastIndex(line[:reqSecIndex], " ")
requestsPerSecond := line[spaceIndex+1 : reqSecIndex]

// Get p50 latency
p50Index := strings.Index(line, "p50=")
spaceAfterP50 := strings.Index(line[p50Index:], " ")
p50Latency := line[p50Index+4 : p50Index+spaceAfterP50]

results = append(results, Metrics{
CommandName: commandName,
RequestsPerSecond: requestsPerSecond,
P50Latency: p50Latency,
})
}
}

return results, nil
}

func createDisplayTable(redisResults []Metrics, sugarDBResults []Metrics) {
if len(sugarDBResults) != len(redisResults) {
fmt.Println("Error: Number of commands in Redis and SugarDB do not match")
}

fmt.Println("Benchmark Performance Results:")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
fmt.Fprint(w, "Command\tRedis (req/sec)\tRedis p50 Latency (msec)\tSugarDB (req/sec)\tSugarDB p50 Latency (msec)\t\n")
for i := 0; i < len(redisResults); i++ {
command := redisResults[i].CommandName
redisReqSec := redisResults[i].RequestsPerSecond
redisLatency := redisResults[i].P50Latency
sugarDBReqSec := sugarDBResults[i].RequestsPerSecond
sugarDBLatency := sugarDBResults[i].P50Latency

fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n", command, redisReqSec, redisLatency, sugarDBReqSec, sugarDBLatency)
}
w.Flush()
}

func main() {

commands, useLocal := getCommandArgs()

// Start a local Redis server, wait a few seconds for it to start
exec.Command("redis-server", "--port", RedisPort).Start()
time.Sleep(2 * time.Second)

// Run benchmark on local Redis server
fmt.Println("-------Running Redis Benchmarks------")
redisResults, err := runBenchmark(RedisPort, commands)
if err != nil {
fmt.Println("Error running benchmark on Redis server:", err)
return
}

if !useLocal {
// Run the packaged SugarDB server, wait a few seconds for it to start
exec.Command("echovault", "--bind-addr=localhost", "--data-dir=persistence").Start()
time.Sleep(5 * time.Second)
}

// Run benchmark on SugarDB server
fmt.Println("-------Running SugarDB Benchmarks------")
sugarDBResults, err := runBenchmark(SugarDBPort, commands)
if err != nil {
fmt.Println("Error running benchmark on SugarDB server:", err)
fmt.Println("Check that the SugarDB server is running")
return
}

// Display results in a table format
createDisplayTable(redisResults, sugarDBResults)

// Kill the local Redis server
exec.Command("pkill", "-f", "redis-server").Run()

if !useLocal {
// Kill the packaged SugarDB server
exec.Command("pkill", "-f", "echovault").Run()
if err := os.RemoveAll("persistence"); err != nil { // Remove persistence directory
fmt.Println("Error removing persistence directory:", err)
}
}
}

0 comments on commit 974ba1b

Please sign in to comment.