返回 筑基・网络云路秘径

长连接与连接池设计

博主
大约 4 分钟

长连接与连接池设计

一、问题引入:短连接的性能瓶颈

1.1 真实案例:微服务通信延迟优化

场景:电商系统微服务间调用,平均响应时间200ms
问题:服务间调用频繁,TCP握手开销占比过高

分析:
┌─────────────────────────────────────────────────────────────┐
│ 短连接问题:                                                 │
│ - 每次调用需TCP三次握手(约50ms)                            │
│ - TLS握手(约100ms)                                         │
│ - 实际数据传输仅10ms                                         │
│ - 连接建立开销占比75%                                        │
├─────────────────────────────────────────────────────────────┤
│ 长连接优化效果:                                             │
│ - 连接复用,消除握手开销                                     │
│ - 平均响应时间:200ms → 50ms                                 │
│ - 系统吞吐量提升4倍                                          │
└─────────────────────────────────────────────────────────────┘

1.2 长连接vs短连接

短连接:
请求 → 建立连接 → 发送数据 → 关闭连接
缺点:频繁握手,开销大

长连接:
建立连接 → 请求1 → 请求2 → 请求3 → ... → 保持连接
优点:减少握手开销,提高吞吐量

二、HTTP Keep-Alive与连接复用

2.1 HTTP Keep-Alive机制

HTTP/1.1 Keep-Alive:
┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  请求头:Connection: keep-alive                              │
│                                                              │
│  响应头:                                                    │
│  Connection: keep-alive                                      │
│  Keep-Alive: timeout=60, max=1000                            │
│                                                              │
│  优势:                                                      │
│  - 复用TCP连接                                               │
│  - 减少延迟                                                  │
│  - 降低CPU消耗                                               │
│                                                              │
│  注意事项:                                                  │
│  - 需要处理连接超时                                          │
│  - 注意连接数限制                                            │
│  - 处理"哑代理"问题                                          │
│                                                              │
└──────────────────────────────────────────────────────────────┘

Nginx配置:
```nginx
keepalive_timeout 65;
keepalive_requests 1000;  # 单个连接最大请求数

### 2.2 HTTP/2多路复用

HTTP/2特性:

  • 单一TCP连接承载多个流
  • 请求响应交错发送
  • 彻底解决队头阻塞
  • 头部压缩(HPACK)

## 三、数据库连接池设计

### 3.1 连接池核心参数

```java
/**
 * HikariCP最佳实践
 */
HikariConfig config = new HikariConfig();

// 连接池大小公式:connections = ((core_count * 2) + effective_spindle_count)
int poolSize = Runtime.getRuntime().availableProcessors() * 2 + 1;
config.setMaximumPoolSize(poolSize);
config.setMinimumIdle(poolSize / 2);

// 超时配置
config.setConnectionTimeout(30000);  // 获取连接超时:30s
config.setIdleTimeout(600000);       // 空闲超时:10min
config.setMaxLifetime(1800000);      // 最大生命周期:30min

// 性能优化
config.setAutoCommit(false);
config.setCachePrepStmts(true);
config.setPrepStmtCacheSize(250);

3.2 连接池监控

@Component
public class ConnectionPoolMonitor {
    
    @Scheduled(fixedRate = 60000)
    public void monitor() {
        HikariPoolMXBean poolMXBean = dataSource.getHikariPoolMXBean();
        
        log.info("Pool Stats - Active: {}, Idle: {}, Wait: {}",
            poolMXBean.getActiveConnections(),
            poolMXBean.getIdleConnections(),
            poolMXBean.getThreadsAwaitingConnection()
        );
    }
}

四、HTTP连接池设计

4.1 OkHttp连接池

/**
 * OkHttp连接池配置
 */
@Bean
public OkHttpClient okHttpClient() {
    ConnectionPool connectionPool = new ConnectionPool(
        50,    // 最大空闲连接
        5,     // 存活时间(分钟)
        TimeUnit.MINUTES
    );

    return new OkHttpClient.Builder()
        .connectionPool(connectionPool)
        .connectTimeout(5, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .connectionPool(connectionPool)
        .protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
        .build();
}

4.2 WebClient连接池

@Bean
public WebClient webClient() {
    ConnectionProvider provider = ConnectionProvider.builder("custom")
        .maxConnections(500)
        .maxIdleTime(Duration.ofSeconds(20))
        .maxLifeTime(Duration.ofSeconds(60))
        .pendingAcquireTimeout(Duration.ofSeconds(60))
        .build();

    HttpClient httpClient = HttpClient.create(provider)
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
        .responseTimeout(Duration.ofSeconds(30));

    return WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .build();
}

五、长连接保活机制

5.1 TCP Keepalive

# Linux TCP Keepalive配置
# 探测间隔
sysctl -w net.ipv4.tcp_keepalive_intvl=30
# 探测次数
sysctl -w net.ipv4.tcp_keepalive_probes=3
# 空闲时间
sysctl -w net.ipv4.tcp_keepalive_time=300

5.2 应用层心跳

/**
 * WebSocket心跳机制
 */
@Component
public class WebSocketHeartbeat {
    
    private static final long HEARTBEAT_INTERVAL = 30000; // 30秒
    
    @Scheduled(fixedRate = HEARTBEAT_INTERVAL)
    public void sendHeartbeat() {
        sessions.forEach(session -> {
            if (session.isOpen()) {
                session.sendMessage(new PingMessage());
            }
        });
    }
}

六、连接池最佳实践

检查清单:
□ 合理设置连接池大小(避免过大或过小)
□ 配置连接超时和空闲检测
□ 启用连接池监控
□ 处理连接泄漏
□ 设置连接最大生命周期
□ 配置健康检查
□ 优雅关闭连接池

系列上一篇TCP拥塞控制深度解析

系列下一篇微服务网络通信模式

知识点测试

读完文章了?来测试一下你对知识点的掌握程度吧!

评论区

使用 GitHub 账号登录后即可发表评论,支持 Markdown 格式。

如果评论系统无法加载,请确保:

  • 您的网络可以访问 GitHub
  • giscus GitHub App 已安装到仓库
  • 仓库已启用 Discussions 功能