Skip to content

Instantly share code, notes, and snippets.

@safoorsafdar
Forked from AhmadElsagheer/benchmark_redis.go
Created September 29, 2020 15:32
Show Gist options
  • Save safoorsafdar/9b5b794a31f6ab09c314d97d1ff3aad4 to your computer and use it in GitHub Desktop.
Save safoorsafdar/9b5b794a31f6ab09c314d97d1ff3aad4 to your computer and use it in GitHub Desktop.
Redis mget vs hget with keys sharing prefix
package benchmark
// Processor: Intel® Core™ i3-2348M CPU @ 2.30GHz × 4
// Memory: 5.7 GiB
//
// Benchmarking on 100,000 records
// - record key length = 50
// - length of common key (prefix) among all records = 15
// - record value length = 5
//
// Results (avg of 10 runs):
// # queries | mget | hmget
// 1 | 142 ms | 128 ms
// 10 | 1395 ms | 1314 ms
// 100 | 13739 ms | 13085 ms
// 1000 | 137224 ms | 127494 ms
import (
"fmt"
"math/rand"
"strconv"
"time"
"github.com/go-redis/redis"
)
var (
queriesCount = []int{1, 10, 100, 1000}
runsCount = 100
)
const (
redisAddress = "localhost:6379"
redisPassword = ""
redisDatabase = 0
recordsCount = 100000
commonKeyLength = 15
keyLength = 50
valueLength = 5
)
var (
client *redis.Client
commonKey string
subkeys []string
values []string
)
func setup() {
rand.Seed(37)
client = redis.NewClient(&redis.Options{
Addr: redisAddress,
Password: redisPassword,
DB: redisDatabase,
})
const letters = "abcdefghijklmnopqrstuvwxyz"
randomString := func(length int) string {
str := make([]byte, length)
for i := range str {
str[i] = letters[rand.Intn(len(letters))]
}
return string(str)
}
commonKey = randomString(commonKeyLength)
subkeys, values = make([]string, recordsCount), make([]string, recordsCount)
for i := range subkeys {
subkeys[i] = randomString(keyLength - commonKeyLength)
values[i] = randomString(valueLength)
}
}
func mgetSetup() []string {
pairs := make([]interface{}, len(subkeys)*2)
keys := make([]string, len(subkeys))
j := 0
for i := range subkeys {
keys[i] = commonKey + subkeys[i]
pairs[j] = keys[i]
pairs[j+1] = values[i]
j += 2
}
client.MSet(pairs...)
return keys
}
func hmgetSetup() (string, []string) {
pairs := make(map[string]interface{}, len(subkeys)*2)
for i := range subkeys {
pairs[subkeys[i]] = values[i]
}
client.HMSet(commonKey, pairs)
return commonKey, subkeys
}
func mget() func() {
client.FlushDB()
fields := mgetSetup()
return func() {
client.MGet(fields...)
}
}
func hmget() func() {
client.FlushDB()
key, fields := hmgetSetup()
return func() {
client.HMGet(key, fields...)
}
}
func benchmark(name string, fn func() func(), count int) int64 {
var totalTime int64
for i := 0; i < runsCount; i++ {
runFunc := fn()
start := time.Now().UnixNano()
for i := 0; i < count; i++ {
runFunc()
}
end := time.Now().UnixNano()
totalTime += (end - start) / 1000000
}
return totalTime / int64(runsCount)
}
func Run() {
setup()
fmt.Printf("%10s | %10s | %10s \n", "# queries", "mget", "hmget")
for _, count := range queriesCount {
t1 := strconv.FormatInt(benchmark("redis mget", mget, count), 10)
t2 := strconv.FormatInt(benchmark("redis hmget", hmget, count), 10)
fmt.Printf("%10s | %10s ms | %10s ms \n", strconv.Itoa(count), t1, t2)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment