\$\begingroup\$
\$\endgroup\$
2
I'm trying to determine best case round-trip times to a redis server. Particularly, I am trying to determine exactly how low I can get the latency on a local instance.
On a technical level, this is pretty easy. However, profiling is always a bit of a dark art, doubly so when network/IPC is involved.
Is this method reasonable?
Here's the numbers I am getting:
localhost:6379: 92.42 μs # local, bare metal on host tcp loopback
/tmp/go/redis.sock: 49.08 μs # local, bare metal on host unix socket
localhost:6380: 276.26 μs # local, docker networking
Which seems in line with my intuition.
package main
import (
"context"
"fmt"
"github.com/go-redis/redis"
"math"
"strconv"
"time"
)
var ctx = context.Background()
func reduceMin(xs []float64) float64 {
if len(xs) == 0 {
return math.NaN()
}
if len(xs) == 1 {
return xs[0]
}
best := math.Min(xs[0], xs[1])
for _, v := range xs {
best = math.Min(best, v)
}
return best
}
func runProfileN(rdb *redis.Client, N int, tries int) (timePer float64, countErrors int){
var val string
totalElapsed := time.Duration(0)
for t := 0; t < tries; t++ {
start := time.Now()
for i := 0; i < N; i++ {
//err := rdb.Set(ctx, "key", fmt.Sprintf("|%3d|val|%3d|", N, i), 0).Err()
err := rdb.Set(ctx, "key", fmt.Sprintf("%d", i), 0).Err()
if err != nil {
panic(err)
}
val, err = rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
i2, err := strconv.Atoi(val)
if err != nil {
panic(err)
}
if i != i2 {
countErrors++
}
}
elapsed := time.Since(start)
totalElapsed += elapsed
}
timePer = float64(totalElapsed.Microseconds()) / float64(N*tries)
return
}
func runProfile(redisAddr string) float64 {
rdb := redis.NewClient(&redis.Options{
Addr: redisAddr,
Password: "", // no password set
DB: 0, // use default DB
})
iters := []int{3, 10, 33, 100, 333, 1000, 3333, 10000}
times := make([]float64, 0)
tries := 5
for _, N := range iters {
timePer, countErrors := runProfileN(rdb, N, tries)
fmt.Printf("%8d: elapsed: %7.2f μs errors: %d\n", N, timePer, countErrors/tries)
times = append(times, timePer)
}
best := reduceMin(times)
fmt.Printf("\n %11s best: %7.2f μs \n", " ", best)
return best
}
func main() {
hosts := []string{"localhost:6379", "/tmp/go/redis.sock", "localhost:6380"}
results := map[string]float64{}
for _, redisAddr := range hosts {
fmt.Println("client on ", redisAddr)
results[redisAddr] = runProfile(redisAddr)
}
for _, redisAddr := range hosts {
fmt.Printf("%30s: %5.2f μs\n", redisAddr, results[redisAddr])
}
}
-
1\$\begingroup\$ would not be simpler to use pprof and benchmarking ? \$\endgroup\$mh-cbon– mh-cbon2020年09月05日 11:19:19 +00:00Commented Sep 5, 2020 at 11:19
-
\$\begingroup\$ Ah, pprof would be a great idea! I'll give that a spin in a bit. \$\endgroup\$DeusXMachina– DeusXMachina2020年09月08日 14:09:03 +00:00Commented Sep 8, 2020 at 14:09
You must log in to answer this question.
lang-golang