为什么需要连接池?
连接池是一个创建和管理连接的缓冲池技术,我们知道,client 每次向 server 发起请求都会创建一个连接。一般一个 rpc 请求消耗的时间可能是几百毫秒到几秒,也就是说在一个比较短的时间内,这个连接就会被销毁。假设我们一秒钟需要处理 20w 个请求,假如不使用连接池的话,可能几万十几万的连接在短时间内都会被创建和销毁,这对 cpu 资源是一个很大的消耗,同时因为我们的端口数是 1~65535,除了一些端口被计算机内部占用,每次 client 创建连接都需要分配一个端口,假如并发量过大的话,可能会出现计算机端口不够用的情况。因此为了提高性能和避免端口不够用的情况,需要连接池
客户端可能同时向多个下游调用,因此一个server地址对应一个子连接池,客户端net.dail时先判断poolManager中是否有该地址的子连接池,如果没有则创建一个子连接池pool,如果有则从该子连接池直接get一个链接。
1.整个pool的管理器结构用一个map存储所有的子连接池,key是address type poolManager struct { opts *Options conns *sync.Map }
2.子连接池结构如下,子连接池管理了本子连接池中所有的连接,所有链接用channel管理
// 子链接池 type pool struct { net.Conn initialCap int // initial capacity 连接池中链接的数量 maxCap int // max capacity maxIdle int // max idle conn number idleTimeout time.Duration // idle timeout dialTimeout time.Duration // dial timeout Dial func(context.Context) (net.Conn, error) conns chan *PoolConn mu sync.RWMutex }
3.每个链接的结构如下:
type PoolConn struct { net.Conn c *channelPool unusable bool // if unusable is true, the conn should be closed mu sync.RWMutex t time.Time // connection idle time dialTimeout time.Duration // connection timeout duration }
连接池用于连接的复用,那么连接什么时候关闭?
1.server关闭连接
2.连接闲置太久