2
\$\begingroup\$

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])
 }
 }
asked Sep 4, 2020 at 23:28
\$\endgroup\$
2
  • 1
    \$\begingroup\$ would not be simpler to use pprof and benchmarking ? \$\endgroup\$ Commented Sep 5, 2020 at 11:19
  • \$\begingroup\$ Ah, pprof would be a great idea! I'll give that a spin in a bit. \$\endgroup\$ Commented Sep 8, 2020 at 14:09

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.