Files
Meshray-Manager/docs/ConnPool 删除决策说明.md
T
2026-06-30 15:14:37 +08:00

6.3 KiB
Raw Blame History

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                   // 最大连接数
    // ...
}

设计目标:

  1. 复用已建立的连接到同一对端
  2. 避免每次都重新拨号(STUN/TURN/WS 等)
  3. 减少资源消耗(每个连接有内存和 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 未来支持:

  1. 多路径传输 (Multipath Transport)

    Peer A ←→ [Path 1] ←→ Peer B
             ↘ [Path 2] ↗
    
    // 需要同时维护多个连接
    
  2. 连接预热 (Connection Preheating)

    // 预先建立一批连接,等待分配
    pool.Preheat(10)  // 预建 10 个连接
    
  3. 高并发场景 (High Concurrency)

    // 大量请求需要快速分配连接
    for i := 0; i < 1000; i++ {
        go func() {
            conn := pool.Get("peer-x")
            // ...
        }()
    }
    

那么可以加 ConnPool,但现在是完全不需要的。


删除决策

删除的文件

core/pool/connpool.go  (102 行)

删除的目录

core/pool/  (空目录已自动清理)

影响评估

  • 无负面影响 - 没有任何地方使用它
  • 代码更简洁 - 减少 102 行无用代码
  • 架构更清晰 - 移除不必要的抽象层
  • 维护更容易 - 少一个需要理解的组件

🎯 技术原则

本次决策遵循的原则

  1. YAGNI 原则

    • You Aren't Gonna Need It
    • 不要为不存在的需求写代码
  2. KISS 原则

    • Keep It Simple, Stupid
    • 不要过度设计
  3. 实事求是

    • 根据实际需求选择技术方案
    • 不要模仿大厂的架构(场景不同)
  4. 保持简洁

    • 简单往往就是最好的
    • 复杂不等于好

📈 改进成果

代码减少

项目 删除行数 删除文件
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 的架构更加简洁清晰! 🎉