[Bug]: 两个 WebSocket 质量问题(资源泄漏 + 日志中泄露密钥)
在使用 github.com/banbox/banexg 进行长期部署时,发现两个独立的问题。
问题 1:WebSocket 客户端注册表无界增长
概述
当 WebSocket 客户端关闭时,并未从交易所的内部客户端注册表中移除。虽然关闭回调路径上执行了部分相关清理逻辑,但注册表条目本身会在整个进程生命周期内一直留存。
触发场景
- 在 Binance USDM 上,每次
listenKey 轮换都会生成一个新的客户端(URL 中嵌入了 listenKey,轮换时注册表的 key 也随之变化)。原有客户端则被遗弃在注册表中。
- 短暂重连也会出现相同的现象:旧条目残留,新条目被添加到另一个 key 下。
影响
随着 WS 客户端的更替频率(重连、listenKey 轮换),内存会出现缓慢的单调增长。每个残留条目都会持有一个 client 结构体及其已关闭的连接。短期内不会致命,但在 7x24 小时持续运行数天乃至数周后即可观察到。
修复建议
在现有的关闭清理路径中一并将该条目从注册表中移除。由于注册表当前在多个 goroutine 之间被无锁地修改,借此修改顺便引入同步机制,使并发访问变得安全。
问题 2:Binance 的 listenKey 以明文形式写入日志
概述
对于 Binance 用户数据流,WebSocket URL 中会嵌入 listenKey——在旧主机上作为路径段,在新的 /private/ws 主机上则作为查询参数。该 URL 字符串随后会在多个层级被打日志:连接、重连、关闭、调试级别的读写,以及 listenKey 续期流程中的告警路径。
影响
listenKey 的有效期较短(约 60 分钟),且只授予对单个账户用户数据流的只读访问权限,因此严重程度较低。但它毕竟是会话凭证,不应以明文形式出现在任何可能被读取日志的位置:日志文件、聚合服务(Loki、ELK、Datadog 等)、错误追踪平台,以及附在工单中的截图等。
修复建议
在 WebSocket URL 进入 logger 之前,先将其中的 listenKey 部分脱敏。需要处理两种形态:旧主机上末尾的路径段,以及新的 /private/ws 上的 listenKey=<value> 查询参数。
[Bug]: 两个 WebSocket 质量问题(资源泄漏 + 日志中泄露密钥)
在使用
github.com/banbox/banexg进行长期部署时,发现两个独立的问题。问题 1:WebSocket 客户端注册表无界增长
概述
当 WebSocket 客户端关闭时,并未从交易所的内部客户端注册表中移除。虽然关闭回调路径上执行了部分相关清理逻辑,但注册表条目本身会在整个进程生命周期内一直留存。
触发场景
listenKey轮换都会生成一个新的客户端(URL 中嵌入了 listenKey,轮换时注册表的 key 也随之变化)。原有客户端则被遗弃在注册表中。影响
随着 WS 客户端的更替频率(重连、listenKey 轮换),内存会出现缓慢的单调增长。每个残留条目都会持有一个 client 结构体及其已关闭的连接。短期内不会致命,但在 7x24 小时持续运行数天乃至数周后即可观察到。
修复建议
在现有的关闭清理路径中一并将该条目从注册表中移除。由于注册表当前在多个 goroutine 之间被无锁地修改,借此修改顺便引入同步机制,使并发访问变得安全。
问题 2:Binance 的
listenKey以明文形式写入日志概述
对于 Binance 用户数据流,WebSocket URL 中会嵌入
listenKey——在旧主机上作为路径段,在新的/private/ws主机上则作为查询参数。该 URL 字符串随后会在多个层级被打日志:连接、重连、关闭、调试级别的读写,以及 listenKey 续期流程中的告警路径。影响
listenKey的有效期较短(约 60 分钟),且只授予对单个账户用户数据流的只读访问权限,因此严重程度较低。但它毕竟是会话凭证,不应以明文形式出现在任何可能被读取日志的位置:日志文件、聚合服务(Loki、ELK、Datadog 等)、错误追踪平台,以及附在工单中的截图等。修复建议
在 WebSocket URL 进入 logger 之前,先将其中的
listenKey部分脱敏。需要处理两种形态:旧主机上末尾的路径段,以及新的/private/ws上的listenKey=<value>查询参数。