1package redis_test 2 3import ( 4 "bytes" 5 "context" 6 "fmt" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/go-redis/redis/v8" 12) 13 14func benchmarkRedisClient(ctx context.Context, poolSize int) *redis.Client { 15 client := redis.NewClient(&redis.Options{ 16 Addr: ":6379", 17 DialTimeout: time.Second, 18 ReadTimeout: time.Second, 19 WriteTimeout: time.Second, 20 PoolSize: poolSize, 21 }) 22 if err := client.FlushDB(ctx).Err(); err != nil { 23 panic(err) 24 } 25 return client 26} 27 28func BenchmarkRedisPing(b *testing.B) { 29 ctx := context.Background() 30 client := benchmarkRedisClient(ctx, 10) 31 defer client.Close() 32 33 b.ResetTimer() 34 35 b.RunParallel(func(pb *testing.PB) { 36 for pb.Next() { 37 if err := client.Ping(ctx).Err(); err != nil { 38 b.Fatal(err) 39 } 40 } 41 }) 42} 43 44func BenchmarkRedisGetNil(b *testing.B) { 45 ctx := context.Background() 46 client := benchmarkRedisClient(ctx, 10) 47 defer client.Close() 48 49 b.ResetTimer() 50 51 b.RunParallel(func(pb *testing.PB) { 52 for pb.Next() { 53 if err := client.Get(ctx, "key").Err(); err != redis.Nil { 54 b.Fatal(err) 55 } 56 } 57 }) 58} 59 60type setStringBenchmark struct { 61 poolSize int 62 valueSize int 63} 64 65func (bm setStringBenchmark) String() string { 66 return fmt.Sprintf("pool=%d value=%d", bm.poolSize, bm.valueSize) 67} 68 69func BenchmarkRedisSetString(b *testing.B) { 70 benchmarks := []setStringBenchmark{ 71 {10, 64}, 72 {10, 1024}, 73 {10, 64 * 1024}, 74 {10, 1024 * 1024}, 75 {10, 10 * 1024 * 1024}, 76 77 {100, 64}, 78 {100, 1024}, 79 {100, 64 * 1024}, 80 {100, 1024 * 1024}, 81 {100, 10 * 1024 * 1024}, 82 } 83 for _, bm := range benchmarks { 84 b.Run(bm.String(), func(b *testing.B) { 85 ctx := context.Background() 86 client := benchmarkRedisClient(ctx, bm.poolSize) 87 defer client.Close() 88 89 value := strings.Repeat("1", bm.valueSize) 90 91 b.ResetTimer() 92 93 b.RunParallel(func(pb *testing.PB) { 94 for pb.Next() { 95 err := client.Set(ctx, "key", value, 0).Err() 96 if err != nil { 97 b.Fatal(err) 98 } 99 } 100 }) 101 }) 102 } 103} 104 105func BenchmarkRedisSetGetBytes(b *testing.B) { 106 ctx := context.Background() 107 client := benchmarkRedisClient(ctx, 10) 108 defer client.Close() 109 110 value := bytes.Repeat([]byte{'1'}, 10000) 111 112 b.ResetTimer() 113 114 b.RunParallel(func(pb *testing.PB) { 115 for pb.Next() { 116 if err := client.Set(ctx, "key", value, 0).Err(); err != nil { 117 b.Fatal(err) 118 } 119 120 got, err := client.Get(ctx, "key").Bytes() 121 if err != nil { 122 b.Fatal(err) 123 } 124 if !bytes.Equal(got, value) { 125 b.Fatalf("got != value") 126 } 127 } 128 }) 129} 130 131func BenchmarkRedisMGet(b *testing.B) { 132 ctx := context.Background() 133 client := benchmarkRedisClient(ctx, 10) 134 defer client.Close() 135 136 if err := client.MSet(ctx, "key1", "hello1", "key2", "hello2").Err(); err != nil { 137 b.Fatal(err) 138 } 139 140 b.ResetTimer() 141 142 b.RunParallel(func(pb *testing.PB) { 143 for pb.Next() { 144 if err := client.MGet(ctx, "key1", "key2").Err(); err != nil { 145 b.Fatal(err) 146 } 147 } 148 }) 149} 150 151func BenchmarkSetExpire(b *testing.B) { 152 ctx := context.Background() 153 client := benchmarkRedisClient(ctx, 10) 154 defer client.Close() 155 156 b.ResetTimer() 157 158 b.RunParallel(func(pb *testing.PB) { 159 for pb.Next() { 160 if err := client.Set(ctx, "key", "hello", 0).Err(); err != nil { 161 b.Fatal(err) 162 } 163 if err := client.Expire(ctx, "key", time.Second).Err(); err != nil { 164 b.Fatal(err) 165 } 166 } 167 }) 168} 169 170func BenchmarkPipeline(b *testing.B) { 171 ctx := context.Background() 172 client := benchmarkRedisClient(ctx, 10) 173 defer client.Close() 174 175 b.ResetTimer() 176 177 b.RunParallel(func(pb *testing.PB) { 178 for pb.Next() { 179 _, err := client.Pipelined(ctx, func(pipe redis.Pipeliner) error { 180 pipe.Set(ctx, "key", "hello", 0) 181 pipe.Expire(ctx, "key", time.Second) 182 return nil 183 }) 184 if err != nil { 185 b.Fatal(err) 186 } 187 } 188 }) 189} 190 191func BenchmarkZAdd(b *testing.B) { 192 ctx := context.Background() 193 client := benchmarkRedisClient(ctx, 10) 194 defer client.Close() 195 196 b.ResetTimer() 197 198 b.RunParallel(func(pb *testing.PB) { 199 for pb.Next() { 200 err := client.ZAdd(ctx, "key", &redis.Z{ 201 Score: float64(1), 202 Member: "hello", 203 }).Err() 204 if err != nil { 205 b.Fatal(err) 206 } 207 } 208 }) 209} 210 211var clientSink *redis.Client 212 213func BenchmarkWithContext(b *testing.B) { 214 ctx := context.Background() 215 rdb := benchmarkRedisClient(ctx, 10) 216 defer rdb.Close() 217 218 b.ResetTimer() 219 b.ReportAllocs() 220 221 for i := 0; i < b.N; i++ { 222 clientSink = rdb.WithContext(ctx) 223 } 224} 225 226var ringSink *redis.Ring 227 228func BenchmarkRingWithContext(b *testing.B) { 229 ctx := context.Background() 230 rdb := redis.NewRing(&redis.RingOptions{}) 231 defer rdb.Close() 232 233 b.ResetTimer() 234 b.ReportAllocs() 235 236 for i := 0; i < b.N; i++ { 237 ringSink = rdb.WithContext(ctx) 238 } 239} 240 241//------------------------------------------------------------------------------ 242 243func newClusterScenario() *clusterScenario { 244 return &clusterScenario{ 245 ports: []string{"8220", "8221", "8222", "8223", "8224", "8225"}, 246 nodeIDs: make([]string, 6), 247 processes: make(map[string]*redisProcess, 6), 248 clients: make(map[string]*redis.Client, 6), 249 } 250} 251 252func BenchmarkClusterPing(b *testing.B) { 253 if testing.Short() { 254 b.Skip("skipping in short mode") 255 } 256 257 ctx := context.Background() 258 cluster := newClusterScenario() 259 if err := startCluster(ctx, cluster); err != nil { 260 b.Fatal(err) 261 } 262 defer cluster.Close() 263 264 client := cluster.newClusterClient(ctx, redisClusterOptions()) 265 defer client.Close() 266 267 b.ResetTimer() 268 269 b.RunParallel(func(pb *testing.PB) { 270 for pb.Next() { 271 err := client.Ping(ctx).Err() 272 if err != nil { 273 b.Fatal(err) 274 } 275 } 276 }) 277} 278 279func BenchmarkClusterSetString(b *testing.B) { 280 if testing.Short() { 281 b.Skip("skipping in short mode") 282 } 283 284 ctx := context.Background() 285 cluster := newClusterScenario() 286 if err := startCluster(ctx, cluster); err != nil { 287 b.Fatal(err) 288 } 289 defer cluster.Close() 290 291 client := cluster.newClusterClient(ctx, redisClusterOptions()) 292 defer client.Close() 293 294 value := string(bytes.Repeat([]byte{'1'}, 10000)) 295 296 b.ResetTimer() 297 298 b.RunParallel(func(pb *testing.PB) { 299 for pb.Next() { 300 err := client.Set(ctx, "key", value, 0).Err() 301 if err != nil { 302 b.Fatal(err) 303 } 304 } 305 }) 306} 307 308var clusterSink *redis.ClusterClient 309 310func BenchmarkClusterWithContext(b *testing.B) { 311 ctx := context.Background() 312 rdb := redis.NewClusterClient(&redis.ClusterOptions{}) 313 defer rdb.Close() 314 315 b.ResetTimer() 316 b.ReportAllocs() 317 318 for i := 0; i < b.N; i++ { 319 clusterSink = rdb.WithContext(ctx) 320 } 321} 322