如何在Golang中测试Redis操作性能_Golang Redis基准测试方法

3次阅读

go-benchmark写redis基准测试需复用client、调用b.resettimer、合理设poolsize、区分do/pipelined/cmdable性能差异、混合读写与错误注入、关注allocs/op及内存影响。

如何在Golang中测试Redis操作性能_Golang Redis基准测试方法

go-benchmarkredis 基准测试脚本

Go 里没有内置的 Redis 性能测试工具,得自己写基准测试(go test -bench),而不是靠 redis-benchmark 这类外部命令——后者测的是网络+服务端,而你通常想验证的是 Go 客户端在真实业务调用路径下的表现。

关键点是:用 testing.B 控制循环次数,复用 redis.Client 实例,避免每次 B.N 都新建连接:

func BenchmarkRedisSet(b *testing.B) {     client := redis.NewClient(&redis.Options{         Addr: "localhost:6379",         PoolSize: 10,     })     defer client.Close()      b.ResetTimer() // 确保只测 Set 操作本身     for i := 0; i < b.N; i++ {         _ = client.Set(context.Background(), fmt.Sprintf("key:%d", i), "value", 0).Err()     } }
  • b.ResetTimer() 必须加,否则初始化 client 的耗时也会被计入
  • PoolSize 要设合理值(比如 10–50),太小会排队,太大可能触发 Redis 连接数限制
  • 别在循环里用 context.WithTimeout 包裹每次调用——它本身有开销;如需超时,统一设在 client 初始化时的 ContextTimeout

区分 DoCmdable 和 pipeline 的性能差异

同一操作,不同调用方式延迟和吞吐量差别明显。比如写入 100 个 key:

  • client.Set(...):走 Cmdable 接口,每次发一个命令,有 RTT 开销
  • client.Pipelined(...):批量发,服务端顺序执行并返回多个响应,适合高并发写入场景
  • client.Do(ctx, "SET", key, val):绕过类型安全封装,直接发原始命令,性能略高但易出错

实测(本地 Redis)中,100 次 Set 平均耗时约 8ms;同样操作用 Pipelined 降到 1.2ms 左右。但注意:Pipelined 不是事务,失败不会回滚,且所有命令必须一次性构造好——不能在 pipeline 里依赖前一条命令的结果。

立即学习go语言免费学习笔记(深入)”;

模拟真实业务压力:混合读写 + 错误注入

SET 或纯 GET 的 benchmark 很容易虚高。真实服务往往是读多写少、带 key pattern、偶发超时或连接中断。

建议在 Benchmark 中混入:

  • 30% GET、60% SET、10% INCR(模拟计数器)
  • 每 100 次操作随机 sleep 1–5ms(模拟业务逻辑间隙)
  • client.Options.MaxRetries = 2 测试重试对 p99 延迟的影响
  • 主动断开连接(如临时停 Redis)观察 connection refused 错误是否被快速捕获,而非卡在 timeout 上

特别注意:如果用 redis.NewFailoverClient,要确保哨兵地址可连,否则首次初始化就会阻塞几秒,直接拖垮 benchmark 结果。

别忽略 redis.Client 的内存与 GC 影响

高频 benchmark 下,redis.Cmd 对象频繁创建/回收会抬高 GC 压力,导致 benchmem 显示 allocs/op 偏高,甚至掩盖真实网络瓶颈。

验证方法:

  • -benchmem 参数运行:go test -bench=. -benchmem
  • 关注 BenchmarkRedisSet-8 100000 12452 ns/op 480 B/op 8 allocs/op 这类输出
  • 若 allocs/op > 5,说明有非必要对象分配;可尝试复用 *redis.StringCmd(不推荐)或改用 Do 降低封装层级

更隐蔽的问题是:client 内部的 ring buffer(如 pool.connReadBuf)默认大小为 64KB,短连接高频场景下可能触发多次扩容,这部分内存不会出现在 benchmark 的 allocs 统计里,但会影响长时间压测的稳定性。

text=ZqhQzanResources