示例说明
开发单机、上线哨兵或集群是常见的演进路径,UniversalClient 的价值是配置结构不变——Addrs 给单节点或集群节点,加 MasterName 与 Sentinels 即切换哨兵模式。超时三件套(拨号、读、写)与池参数是线上纪律:过长的超时让慢查询拖垮调用方,过小的池在高并发下排队等待。
技术要点
- 一份配置覆盖三种部署拓扑
- 池大小与保活连接数显式声明
- Pipeline 批量往返摊薄延迟
代码解读
newRedisClient 构造 UniversalOptions:两秒拨号、八百毫秒读写、二十连接配五个保活,重试两次且退避封顶。main 用 Pipeline 把 SET 与 TTL 两条命令打包一次往返——两条独立往返的网络延迟合并为一。Exec 返回后从各命令对象取结果。
使用建议
读写超时要大于最慢合法命令耗时。池大小按 Redis 服务端的连接预算分配。生产环境开启只读副本读写分离要评估一致性。
代码示例
package main
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
func newRedisClient() redis.UniversalClient {
opts := &redis.UniversalOptions{
Addrs: []string{"127.0.0.1:6379"},
DialTimeout: 2 * time.Second,
ReadTimeout: 800 * time.Millisecond,
WriteTimeout: 800 * time.Millisecond,
PoolSize: 20,
MinIdleConns: 5,
PoolTimeout: 2 * time.Second,
MaxIdleConns: 10,
ConnMaxIdleTime: 5 * time.Minute,
// 同一份配置可透明升级为哨兵或集群:
// MasterName: "mymaster",
// Sentinels: []*redis.SentinelAddr{{...}},
// 或 Addrs 直接给多个集群节点
MaxRetries: 2,
MinRetryBackoff: 50 * time.Millisecond,
MaxRetryBackoff: 500 * time.Millisecond,
}
return redis.NewUniversalClient(opts)
}
func main() {
client := newRedisClient()
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
pipe := client.Pipeline()
setCmd := pipe.Set(ctx, "session:42", "active", 30*time.Minute)
ttlCmd := pipe.TTL(ctx, "session:42")
_, err := pipe.Exec(ctx)
if err != nil {
fmt.Println("pipeline failed:", err)
return
}
fmt.Println("set ok:", setCmd.Val(), "ttl:", ttlCmd.Val())
defer client.Close()
}