6.3 KiB
6.3 KiB
ConnPool 删除决策说明
删除时间: 2026-03-24
状态: ✅ 已完成
决策依据: YAGNI 原则(You Aren't Gonna Need It)
📋 ConnPool 的设计目的
原始意图
// ConnPool 连接池 - 复用 net.Conn 以减少资源消耗
type ConnPool struct {
pools map[string][]net.Conn // key: 对端标识,value: 连接池
maxSize int // 最大连接数
// ...
}
设计目标:
- ✅ 复用已建立的连接到同一对端
- ✅ 避免每次都重新拨号(STUN/TURN/WS 等)
- ✅ 减少资源消耗(每个连接有内存和 goroutine 开销)
🤔 是否需要保留?
现状分析
实际情况
在 MeshRay 的 P2P 通信模型中:
Peer A ←→ Peer B
↑
└── 只需要一个连接
特点:
- ✅ 每个 Peer 对之间只需要一个活跃连接
- ✅ 连接建立后持续使用,直到断开
- ✅ 不需要"池"的概念(不是 Web 服务器的高并发场景)
ConnPool vs ConnectionManager
| 方案 | ConnPool(连接池) | ConnectionManager(连接管理器) |
|---|---|---|
| 复杂度 | 高(102 行代码) | 低(~50 行代码) |
| 功能 | 连接池复用、大小限制、健康检查 | 简单映射管理、一对一连接 |
| 数据结构 | map[string][]net.Conn |
map[string]net.Conn |
| 适用场景 | 高并发、多连接复用 | 一对一 P2P 连接 |
| 维护成本 | 高(需要管理池生命周期) | 低(简单的 CRUD) |
| 当前需求 | ❌ 不需要 | ✅ 正好满足 |
🎯 删除理由
1. 过度设计
ConnPool 的复杂逻辑:
// 需要管理:
- 连接池大小限制(maxSize)
- 连接的获取(Get)
- 连接的归还(Put)
- 连接的健康检查
- 过期连接的清理(Clear)
- 并发控制(mutex)
但实际只需要:
// ConnectionManager 就够了:
- 保存连接(Set)
- 获取连接(Get)
- 关闭连接(Close)
2. 没有实际使用
审查结果:
# 搜索整个项目
grep -r "ConnPool" .
grep -r "NewConnPool" .
grep -r "pool\.Get\|pool\.Put" .
发现:
- ❌ 没有任何地方使用 ConnPool
- ❌ 只在文档中提到过
- ❌ 是"为未来可能的需求"提前写的代码
3. 违反 YAGNI 原则
YAGNI = You Aren't Gonna Need It(你不会需要的)
ConnPool 的问题:
- ❌ 为不存在的"高并发场景"提前优化
- ❌ 增加了 102 行代码的维护成本
- ❌ 让架构变得更复杂
- ❷ 实际上完全用不到
4. 正确的做法
在 connection_manager.go 中直接管理:
type ConnectionManager struct {
mu sync.RWMutex
conns map[string]net.Conn // key: peerID
logger *zap.Logger
}
func (m *ConnectionManager) GetConnection(peerID string) net.Conn {
m.mu.RLock()
defer m.mu.RUnlock()
return m.conns[peerID]
}
func (m *ConnectionManager) SetConnection(peerID string, conn net.Conn) {
m.mu.Lock()
defer m.mu.Unlock()
// 关闭旧连接(如果有)
if oldConn, exists := m.conns[peerID]; exists {
oldConn.Close()
}
m.conns[peerID] = conn
}
func (m *ConnectionManager) CloseConnection(peerID string) {
m.mu.Lock()
defer m.mu.Unlock()
if conn, exists := m.conns[peerID]; exists {
conn.Close()
delete(m.conns, peerID)
}
}
优点:
- ✅ 简单直接 - 就是普通的 map 管理
- ✅ 每个 Peer 一个连接 - 符合实际需求
- ✅ 无需连接池 - 不需要复杂的复用逻辑
- ✅ 易于理解和维护
📊 如果未来真的需要 ConnPool
什么情况下需要?
如果 MeshRay 未来支持:
-
多路径传输 (Multipath Transport)
Peer A ←→ [Path 1] ←→ Peer B ↘ [Path 2] ↗ // 需要同时维护多个连接 -
连接预热 (Connection Preheating)
// 预先建立一批连接,等待分配 pool.Preheat(10) // 预建 10 个连接 -
高并发场景 (High Concurrency)
// 大量请求需要快速分配连接 for i := 0; i < 1000; i++ { go func() { conn := pool.Get("peer-x") // ... }() }
那么可以加 ConnPool,但现在是完全不需要的。
✅ 删除决策
删除的文件
core/pool/connpool.go (102 行)
删除的目录
core/pool/ (空目录已自动清理)
影响评估
- ✅ 无负面影响 - 没有任何地方使用它
- ✅ 代码更简洁 - 减少 102 行无用代码
- ✅ 架构更清晰 - 移除不必要的抽象层
- ✅ 维护更容易 - 少一个需要理解的组件
🎯 技术原则
本次决策遵循的原则
-
YAGNI 原则
- ✅ You Aren't Gonna Need It
- ❌ 不要为不存在的需求写代码
-
KISS 原则
- ✅ Keep It Simple, Stupid
- ❌ 不要过度设计
-
实事求是
- ✅ 根据实际需求选择技术方案
- ❌ 不要模仿大厂的架构(场景不同)
-
保持简洁
- ✅ 简单往往就是最好的
- ❌ 复杂不等于好
📈 改进成果
代码减少
| 项目 | 删除行数 | 删除文件 |
|---|---|---|
| ConnPool | 102 行 | 1 个文件 |
| pool 目录 | - | 1 个空目录 |
架构简化
删除前:
core/
├── pool/
│ └── connpool.go # 连接池(未使用)
├── connection_manager.go # 连接管理器
删除后:
core/
├── connection_manager.go # 连接管理器(足够用了)
🎉 总结
核心改进
- ✅ 删除过度设计 - ConnPool 对于 P2P 场景是多余的
- ✅ 回归本质 - 简单的 map 管理就够用了
- ✅ 代码简洁 - 减少 102 行无用代码
- ✅ 易于维护 - 架构更清晰
经验教训
- ✅ 不要提前优化 - 除非证明需要
- ✅ 按需实现 - 根据实际需求写代码
- ✅ 保持简单 - 简单往往就是最好的
- ✅ 敢于删除 - 没用的代码就删掉
删除完成时间: 2026-03-24
状态: ✅ 已完成
评价: ✅ 正确的决策
ConnPool 删除圆满完成!MeshRay 的架构更加简洁清晰! 🎉