1. 连接池核心原理:OkHttp连接复用机制、Keep‑Alive策略、连接池数据结构
1.1 为什么需要连接池
每次 HTTP 请求都新建 TCP 连接会带来三次握手 + TLS 握手(HTTPS)的开销,延迟可达 50‑200ms。连接池通过复用已建立的连接消除这些握手成本,同时降低服务端连接数,减少资源消耗。
1.2 连接复用机制
OkHttp 的 ConnectionPool 管理所有空闲的 RealConnection。当发起请求时,ExchangeFinder 按以下优先级寻找可用连接:
- 查找当前
RealConnection是否已被占用的连接(同一 host/port)。 - 从连接池的空闲队列中按 LRU 策略取出一个连接。
- 若未找到,则新建连接并注册到池中。
复用成功后,请求直接复用底层 Socket,无需重复 TCP/TLS 握手。
1.3 Keep‑Alive 策略
HTTP 1.1 默认使用 Connection: keep-alive。OkHttp 通过两个参数控制空闲连接存活:
| 参数 | 默认值 | 说明 |
|---|---|---|
maxIdleConnections | 5 | 每 host 最大空闲连接数,超过则逐出最久未使用的连接 |
keepAliveDuration | 5 分钟 | 空闲连接的最大存活时间,超过则被关闭 |
当连接空闲超过 keepAliveDuration 且未被复用时,ConnectionPool 的清理线程会将其关闭并移出队列。
1.4 连接池数据结构
核心数据结构如下:
Deque<RealConnection> connections– 按使用顺序存储所有连接(包括空闲和在用)RouteDatabase routeDatabase– 记录连接失败的路由,避免频繁重试cleanupRunnable– 后台任务,每隔 1 秒检查并清理过期空闲连接
每个 RealConnection 内部维护一个 List<Reference<StreamAllocation>> allocations,记录当前正在使用该连接的请求数量。当 allocations 为空时,连接变为空闲状态。
1.5 配置连接池
通过 ConnectionPool 构造方法设置参数,并在 OkHttpClient.Builder 中注入:
// 创建连接池:最多保持 10 个空闲连接,空闲存活 30 秒
ConnectionPool pool = new ConnectionPool(10, 30, TimeUnit.SECONDS);
OkHttpClient client = new OkHttpClient.Builder()
.connectionPool(pool)
.build();
参数说明:
maxIdleConnections– 每 host 最大空闲连接数,避免短连接过多导致内存泄漏keepAliveDuration– 空闲连接超时时间,建议根据应用网络行为调整(如 30s‑120s)
1.6 调试验证连接复用
添加 EventListener 观察连接创建和复用事件:
class ConnectionInspector extends EventListener {
@Override
public void connectionAcquired(Call call, Connection connection) {
System.out.println("Connection acquired: " + connection.socket().getRemoteSocketAddress());
}
@Override
public void connectionReleased(Call call, Connection connection) {
System.out.println("Connection released: " + connection);
}
@Override
public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) {
System.out.println("New connection start: " + inetSocketAddress);
}
}
OkHttpClient client = new OkHttpClient.Builder()
.connectionPool(new ConnectionPool(5, 5, TimeUnit.SECONDS))
.eventListener(new ConnectionInspector())
.build();
连续发起两次相同 host 的请求,观察日志:
- 第一次:
New connection start→Connection acquired - 第二次:直接输出
Connection acquired(复用),无connectStart
1.7 性能提升数据
| 场景 | 无连接池(每次新建) | 有连接池(复用) | 提升比例 |
|---|---|---|---|
| 同一 host 连续 10 次请求(HTTP) | ~450ms | ~80ms | 约 82% 延迟降低 |
| 同一 host 连续 10 次请求(HTTPS) | ~1.8s | ~200ms | 约 89% 延迟降低 |
| 服务器连接数(压力测试) | 瞬时 100 个连接 | 压到 5‑10 个连接 | 资源消耗降低 90%+ |
实际收益取决于 Keep‑Alive 时长和请求频率;建议在生产环境中使用默认值(5 个空闲 / 5 分钟),然后根据压测调整。
关键结论:连接池通过复用 TCP/TLS 连接,大幅降低延迟和服务器资源消耗。默认配置适用于多数场景,但高并发短连接业务(如实时推送)应缩短
keepAliveDuration 并增大 maxIdleConnections。