上传时 WebSocket 心跳超时的排查
上传变快之后,有些上传开始报 “Tunnel offline”。
改了什么
hostc 所有请求都走一条 WebSocket,每个流有自己的流控。上传窗口原来固定为 256 KiB,每个往返最多传一个窗口,长距离链路上这就是硬上限。所以我们让窗口在成为瓶颈时变宽,每个请求最大 4 MiB。
上传确实变快了,但线上测试的 16 次上传里失败了 2 次。
为什么失败
CLI 每 15 秒发一次 ping,10 秒内没收到 pong 就断开。我们在上传中途把链路拖慢 20 秒,复现了问题。
WebSocket 是一条有序的字节流,pong 排在这条连接上所有已发送的数据后面。窗口小的时候影响不大,但有 4 MiB 在途、链路又变慢时,pong 可能要等 10 秒以上。
所以连接其实是通的,只是 pong 来晚了,CLI 就把它当成断线处理。
怎么修
只要收到消息,就说明连接还活着。所以现在连接上收到任何数据都会清掉超时,不只是 pong。连接真的断了就什么都收不到,照样会被断开。
修复后,同样 20 秒的掉速可以传完,不会重连。
怎么复现的
修复只有三行,复现花的时间更长。正常上传不会失败,本地测试环境的链路又很稳定。最后靠一个代理:上传开始 1.5 秒后,把速度降到 200 KB/s,持续 20 秒。这样新版本会断开连接,上一个版本却能撑过去,由此确认原因是窗口变宽。
回归测试用的是一个假服务端和很短的超时。一个用例在 ping 之后什么都不发,期望连接被断开;另一个让 pong 迟到,但数据一直在到,期望连接保持。第二个验证修复有效,第一个确认断线检测还在。
小结
心跳和数据走同一条有序连接时,心跳会排在数据后面,所以超时不一定代表断线,也可能只是连接很忙。修复已随 hostc 2.1.2 发布。
一条命令拿到公网地址,免费,不用注册
npx hostc@latest 3000