应使用 aerospike-client-go/v6 版本,因其修复了 v1.9.x 及更早版本在 key_not_found_error 场景下的 tcp 连接泄漏问题;初始化需显式传入策略对象并配置多节点,连接队列大小默认 256,超时设为 50ms。

直接上结论:用 aerospike-client-go/v6,配好连接池和错误分类处理,别用 v1.9.x 及更早版本——它们在 KEY_NOT_FOUND_ERROR 场景下会泄漏 TCP 连接,高并发时必崩。
选对客户端版本和初始化方式
2024 年起官方主推 v6,它修复了 v1.x 的连接池泄漏问题,并默认启用连接复用、自动重试和健康探测。初始化时不要裸写 as.NewClient("localhost", 3000),必须显式传入策略对象:
-
as.NewClientWithPolicyAndHosts(policy, as.NewHost("10.0.1.5", 3000), as.NewHost("10.0.1.6", 3000))—— 多节点支持靠这个,不是靠字符串拼接 -
policy.ConnectionQueueSize = 256—— 默认 256 足够,压测发现超时再调大,别盲目设成 1024 -
policy.Timeout = 50 * time.Millisecond—— Aerospike 本地集群 P99 延迟通常
Get / Put 必须区分 KEY_NOT_FOUND_ERROR 和真实错误
这是最容易踩的坑:client.Get() 返回 nil, err 时,err 很可能是 types.KEY_NOT_FOUND_ERROR(返回码 2),它不是异常,而是业务常态。若不做类型断言就 panic 或 log.Fatal,连接池会持续丢连接。
- 正确写法是:
if ae, ok := err.(types.AerospikeError); ok && ae.ResultCode() == types.KEY_NOT_FOUND_ERROR - 此时应直接返回空值或默认值,**不调用
defer client.Close(),也不关闭 policy 上下文** - 所有非 2/14(
SERVER_ERROR)的错误码都该走告警通道,比如RESULT_FAIL(1)表示服务端拒绝,大概率是 bin 超限或 namespace 满
批量操作要用 BatchRead / BatchWrite,别循环单条
单 key Get 在千级 QPS 下延迟尚可,但万级并发+百 key 批量查时,RT 会陡增 3–5 倍。Aerospike 的 batch 是服务端原生支持的,一次网络往返就能完成。
-
keys := []*as.Key{key1, key2, ..., key100},然后client.BatchRead(nil, keys) - 返回的
*as.BatchRecords中每个 record 都带独立Err字段,仍需逐个判断是否KEY_NOT_FOUND_ERROR - 避免混合类型 batch:不要把
Put和Get放进同一个 batch,v6 不支持
连接泄漏的典型现象和快速确认方法
当你看到 dial tcp 127.0.0.1:3000: cannot assign requested address 或 command execution timed out,且 netstat -an | grep :3000 | wc -l 超过 65535,基本就是连接池耗尽。
- 立刻检查
go version和go list -m all | grep aerospike,确认不是 v1.9.x - 在
client.Get后加一行:fmt.Printf("err=%v, isKeyNotFound=%t\n", err, err != nil && isErrorType(err, types.KEY_NOT_FOUND_ERROR)) - 临时把
policy.MaxConnsPerNode设为 8,观察错误是否收敛——如果收敛,说明旧逻辑在疯狂建新连接没释放
真正难处理的不是连不上,而是连上了却因错误分类不清,让连接静默失效。上线前务必用 go test -bench=. 跑一轮含 KEY_NOT_FOUND_ERROR 的混合读写压测,否则等流量上来再修,代价远高于初始化多写三行类型判断。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











