业务场景
在高并发的 Go 服务中,业务通常通过 redigo 连接池复用连接来访问 Redis。此时常遇到以下问题:
连接负载倾斜: redigo 官方连接池从队头取连接、又将已用连接放回队头,导致最热的少数连接被持续复用,其余连接长期空闲。
Proxy 节点压力不均: 在云上多 Proxy 节点的架构中,连接分布不均会使部分 Proxy 节点承载过高请求,成为性能瓶颈。
扩容收益不明显: 由于请求集中在少数连接与节点上,即使增加实例规格或节点,整体吞吐也难以线性提升。
通过将连接池改造为轮询(连接用完放回队尾),可使连接被均衡使用,缓解上述倾斜问题,提升高并发场景下的稳定性与资源利用率。
背景信息
redigo 官方连接池的连接存取机制如下:
官方连接池仅支持从队头取连接(popFront),并将已用连接放回队头(pushFront)。
已使用的连接放回队头后又从队头取出,导致最热的连接被持续重复使用。
连接无法被轮询使用,最终引起 Proxy 连接或负载不均衡问题。
针对该问题,可修改 redigo 源代码中的
pool.go 文件,增加 pushBack 方法,将已使用的连接放回队尾,从而实现连接轮询。前提条件
已创建云分布式缓存数据库实例,并获取实例的连接地址与访问密码。
已安装 Go 运行环境,并在项目中引入 redigo 依赖。
具备修改 redigo 依赖源码的条件(例如通过私有 fork 或 vendor 目录管理改动)。
说明:
本文的
pushBack 方法与 Lifo 字段并非 redigo 官方自带,而是对官方 pool.go 的自定义改造。redigo 官方连接池(截至当前 master)的 idleList 仅提供 pushFront、popFront、popBack 方法,归还连接时采用 pushFront(放回队头),本身即为 LIFO(后进先出)行为,因此官方无 Lifo 配置项。若需将连接改为 FIFO(轮询)以均衡使用,需按本文自行增加 pushBack 并改造归还逻辑。具体请以 redigo 官方源码 为准,并自行编译验证。操作步骤
步骤1:在 idleList 中新增 pushBack 方法
在
pool.go 中为 idleList 增加 pushBack 方法,将连接加入队尾:// idle connect push list backfunc (l *idleList) pushBack(pc *poolConn) {if l.count == 0 {l.front = pcl.back = pcpc.prev = nilpc.next = nil} else {pc.prev = l.backl.back.next = pcl.back = pcpc.next = nil}l.count++}
步骤2:在 Pool 结构体中新增 Lifo 配置字段
为
Pool 结构体新增 Lifo 字段,用于控制连接放回位置:// idle connection in the pool method// True: pushBack, False: pushFront, default FalseLifo bool
步骤3:在归还连接逻辑中根据 Lifo 判断放回位置
在归还连接(
put)逻辑中,根据 Lifo 决定连接放回队头还是队尾:if p.Lifo == true {p.idle.pushBack(pc) // 放回队尾} else {p.idle.pushFront(pc) // 放回队头(默认)}
步骤4:初始化连接池时开启 Lifo
创建连接池时,将
Lifo 设置为 true,使已使用的连接放回队尾,实现连接轮询、均衡负载:// 建立连接池redisClient = &redis.Pool{MaxIdle: maxIdle,MaxActive: maxActive,IdleTimeout: MaxIdleTimeout * time.Second,Wait: true,Lifo: true, // 设置为 true,将已用连接放回队尾Dial: func() (redis.Conn, error) {con, err := redis.Dial("tcp", conf["Host"].(string),redis.DialPassword(conf["Password"].(string)),redis.DialDatabase(int(conf["Db"].(int64))),redis.DialConnectTimeout(timeout*time.Second),redis.DialReadTimeout(timeout*time.Second),redis.DialWriteTimeout(timeout*time.Second))if err != nil {return nil, err}return con, nil},}
验证方法
完成改造并设置
Lifo: true 后,可通过以下方式确认连接被均衡使用:在业务持续请求一段时间后,通过实例监控观察各 Proxy 节点的连接数与请求量是否趋于均衡,不再集中在少数节点。
在客户端侧统计连接的使用分布,确认请求不再长期集中在少数固定连接上。
常见问题
Q:改造后升级 redigo 依赖,改动丢失怎么办?
直接修改第三方库源码后,升级依赖时改动可能被覆盖。建议通过私有 fork 或 vendor 目录管理该改动,并在充分测试后再应用于生产环境。
Q:官方 redigo 自带该改造吗?升级后是否需要重新处理?
不自带。截至当前 master,redigo 官方连接池并无
Lifo 字段与 pushBack 方法,归还连接采用 pushFront(放回队头),本身为 LIFO 行为。本文的 FIFO 轮询能力属自定义改造,升级依赖后需重新合入该改动(建议以 fork 或 vendor 管理)。应用前请对照所用版本的官方源码确认并自行编译验证。