You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.2 KiB
6.2 KiB
客户端连接池
概述
客户端连接池(Client Pool)是一个用于管理和复用客户端连接的工具,可以显著提高客户端应用的性能和资源利用率。
作用
- 连接复用:复用已建立的连接,避免频繁创建和销毁连接,减少系统开销
- 连接管理:自动管理连接的生命周期,包括连接创建、验证、清理等
- 并发控制:限制最大连接数,防止连接数过多导致服务器压力
- 资源优化:预创建最小连接数,提高响应速度;自动清理空闲连接,节省资源
- 故障恢复:自动检测和移除无效连接,创建新连接替代
使用方法
1. 创建连接池
import "github.com/noahlann/nnet/pkg/nnet"
// 创建连接池配置
poolConfig := &nnet.ClientPoolConfig{
MaxSize: 10, // 最大连接数
MinSize: 2, // 最小连接数(预创建)
ClientConfig: &nnet.ClientConfig{
Addr: "tcp://127.0.0.1:8888",
ConnectTimeout: 5 * time.Second,
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
},
AcquireTimeout: 5 * time.Second, // 获取连接超时时间
IdleTimeout: 5 * time.Minute, // 空闲连接超时时间
}
// 创建连接池
pool, err := nnet.NewClientPool(poolConfig)
if err != nil {
log.Fatalf("Failed to create connection pool: %v", err)
}
defer pool.Close()
2. 获取和释放连接
// 获取连接
client, err := pool.Acquire()
if err != nil {
log.Fatalf("Failed to acquire connection: %v", err)
}
// 使用连接
request := []byte("echo hello\n")
resp, err := client.Request(request, 5*time.Second)
if err != nil {
log.Printf("Request failed: %v", err)
} else {
fmt.Printf("Response: %s", string(resp))
}
// 释放连接(归还到连接池)
pool.Release(client)
3. 并发使用
var wg sync.WaitGroup
for i := 0; i < numRequests; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// 从连接池获取连接
client, err := pool.Acquire()
if err != nil {
log.Printf("Failed to acquire connection: %v", err)
return
}
// 使用完毕后释放连接
defer pool.Release(client)
// 使用连接发送请求
request := []byte(fmt.Sprintf("echo request-%d\n", id))
resp, err := client.Request(request, 5*time.Second)
if err != nil {
log.Printf("Request failed: %v", err)
return
}
fmt.Printf("Response: %s", string(resp))
}(i)
}
wg.Wait()
4. 检查连接池状态
// 获取当前连接数
size := pool.Size()
// 获取可用连接数
available := pool.Available()
// 检查连接池是否已关闭
isClosed := pool.IsClosed()
fmt.Printf("Pool status: Size=%d, Available=%d, IsClosed=%v\n",
size, available, isClosed)
配置说明
ClientPoolConfig
- MaxSize (int): 最大连接数,默认值为 10
- MinSize (int): 最小连接数(预创建),默认值为 2
- ClientConfig (*ClientConfig): 客户端配置(地址、超时时间等)
- AcquireTimeout (time.Duration): 获取连接超时时间,默认值为 10 秒
- IdleTimeout (time.Duration): 空闲连接超时时间,默认值为 5 分钟
默认配置
使用 nnet.DefaultClientPoolConfig() 获取默认配置:
config := nnet.DefaultClientPoolConfig()
config.ClientConfig.Addr = "tcp://127.0.0.1:8888"
pool, err := nnet.NewClientPool(config)
实现细节
1. 连接管理
- 连接池在创建时会预创建
MinSize个连接 - 当连接数小于
MaxSize时,可以动态创建新连接 - 连接在使用完毕后会被归还到连接池,供后续复用
2. 连接验证
- 从连接池获取连接时,会自动检查连接是否有效
- 如果连接无效,会自动创建新连接替代
- 释放连接时,也会检查连接有效性,无效连接会被移除
3. 空闲连接清理
- 如果配置了
IdleTimeout,连接池会定期检查并清理无效连接 - 清理间隔为
IdleTimeout / 2,确保及时清理无效连接
4. 并发安全
- 连接池使用原子操作和互斥锁保证并发安全
Acquire和Release操作是线程安全的- 多个 goroutine 可以安全地并发使用连接池
5. 连接池关闭
- 调用
Close()方法会关闭所有连接并停止所有 goroutine - 关闭后的连接池不能再次使用
- 已获取的连接在释放时会被关闭(如果连接池已关闭)
最佳实践
- 合理设置连接数:根据实际并发需求设置
MaxSize,避免连接数过多或过少 - 及时释放连接:使用
defer pool.Release(client)确保连接被正确释放 - 处理错误:始终检查
Acquire()和Request()的返回错误 - 资源清理:在程序退出前调用
pool.Close()关闭连接池 - 超时设置:合理设置
AcquireTimeout和IdleTimeout,避免资源浪费
示例
完整示例请参考:
examples/client_pool/server.go- 服务器示例examples/client_pool/client.go- 客户端连接池示例
API 参考
ClientPool
Acquire() (Client, error)- 获取连接Release(client Client) error- 释放连接Close() error- 关闭连接池Size() int- 获取当前连接数Available() int- 获取可用连接数IsClosed() bool- 检查连接池是否已关闭
ClientPoolConfig
MaxSize int- 最大连接数MinSize int- 最小连接数ClientConfig *ClientConfig- 客户端配置AcquireTimeout time.Duration- 获取连接超时时间IdleTimeout time.Duration- 空闲连接超时时间
实现状态
✅ 已实现
- 连接池基本功能(获取、释放、关闭)
- 连接验证和自动替换
- 并发安全
- 空闲连接清理
- 最大连接数限制
- 最小连接数预创建
- 公共API导出
- 单元测试
- 使用示例
注意事项
- 连接池目前仅支持 TCP 客户端
- 连接池不支持连接的健康检查(除了连接有效性检查)
- 空闲连接清理是基于连接有效性,而不是基于最后使用时间(简化实现)
- 连接池关闭后,已获取的连接在使用完毕后会被关闭