基于 Go 语言开发的轻量级TCP长连接并发服务器框架。
- 并发处理模型:采用协程池与任务队列结合的设计,分离读写协程实现 I/O 与业务逻辑并发处理,支持万级并发连接。
- 高效传输协议:基于 TLV 格式的二进制协议实现,有效解决 TCP 粘包/拆包问题。
- 架构设计:服务器状态管理、连接管理器、可扩展协议接口。
- 场景组件:心跳检测与断线重连机制。
-
客户端初始化与发送逻辑顺序问题
现象 :测试时客户端未完成初始化即执行发送逻辑,引发空指针异常。
问题本质 :协程调度顺序不确定导致:
- 连接未初始化完成
- 发送逻辑提前执行
解决方案 :
- 引入 ready 管道同步协程
- 调整关键协程启动顺序
- 非关键路径保留并发
经验总结:
- 执行并发逻辑需确保依赖实例初始化完整
-
高并发场景下的服务端稳定性问题
现象 :压力测试时端口耗尽导致客户端断连,服务端崩溃。
问题本质 :
- 连接异常处理机制缺陷
- 并发协程资源竞争
- 任务执行完整性不足
改进方案 :
-
状态管理 :
-
原子变量标记连接状态
-
sync.WaitGroup 跟踪任务
-
-
执行流程优化 :
reader异常 -> 设置关闭状态 -> stop流程 -> wg.Wait -> workpool处理遗留任务 -> writer尽力发送 -> wg.Done -> 清理资源
-
容错设计 :
- 任务提交不检查连接状态
- 写协程统一处理异常
- 提供用户级熔断接口
-
性能考量 :
- "尽力而为"处理异常任务
- 优雅关闭分阶段执行(停读 -> 停写 -> 清理)
经验总结:
- 资源释放需保证执行完整性
-
服务端异步启动后 stop 在大量并发连接下的死锁问题
现象:服务端在异步启动后调用 Stop 方法时,面对大量并发连接场景,程序因死锁异常退出。
问题本质 :
-
锁竞争与链式调用 :
-
原connmanager模块使用sync.Mutex保护连接集合(map),Stop操作需遍历所有连并逐个调用conn.Stop()。
-
conn.Stop()内部可能再次申请锁(如连接自身的状态锁),导致嵌套锁竞争 。
-
当connmanager的锁未释放时,调用conn.Stop()可能因等待连接内部锁而阻塞,形成死锁链。
-
-
资源清理顺序缺陷 :
- 未明确资源释放的优先级,导致连接关闭时可能仍在处理旧任务或接收新请求。
解决方案 :
- 数据结构优化 :
- 替换为sync.Map : 将连接集合从普通map+Mutex替换为sync.Map,利用其无锁并发特性,避免遍历时的锁竞争。
- 原子状态管理 : 使用atomic包标记服务端状态,确保状态变更的原子性,避免竞态。
经验总结 :
- 避免嵌套锁 :优先使用并发安全的数据结构(如sync.Map)减少锁粒度。
- 资源生命周期管理 :明确资源创建、使用、销毁的顺序,避免循环依赖。
- 优雅退出设计 :
- 分阶段关闭(先停读,再停写,最后清理)。
- 通过原子状态和WaitGroup确保执行完整性。
- 压测验证必要性 :高并发场景必须通过压力测试暴露隐藏的竞态和死锁问题。
-