问题描述
客户使用DCDN的WebSocket业务,偶发出现无法访问的情况,线上有1%左右的失败率。根据客户沟通,该问题并不是必现的,目前是其中一位同事家里的wifi网络下能复现问题,而且重启家里的光猫以后能正常,但一段时间以后又会出现问题。
问题排查
1. 客户端信息
尝试让客户复现问题,提供客户端的Netwrok信息和客户端抓包信息。从抓包信息看,是源站响应了500。进一步跟客户确认源站逻辑,根据客户的反馈是源站会先校验Upgrade: websocket 这个请求头,如果没有这个请求头就会返回500。但是奇怪的是,根据抓包文件看,客户端明明是带了Upgrade: websocket请求头的,因此怀疑是DCDN节点转发的问题。
根据WebSocket的RFC协议文档可以知道
- Websocket请求必须包含一个Upgrade header字段,它的值必须包含"websocket"。
- WebSocket请求必须包含一个Connection header字段,它的值必须包含"Upgrade"。
2. 模拟访问测试
根据抓包信息,使用curl指定到对应的DCDN请求模拟发WebSocket请求测试,发现在客户侧能稳定复现的情况下,我们curl测试并不能复现,排查来看又跟节点没有关系。
curl -sv 'http://xxx.xxx.com/' -H'Connection: Upgrade' -H'Upgrade: websocket' -H'Sec-WebSocket-Key: pCnMykJwUTQB14FCbP2Beg==' -H'Sec-WebSocket-Version: 13' -H'Origin:http://xxx.xxx.com' -H'Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits' -H'Accept-Encoding: gzip, deflate' -x 116.253.29.212:80
3. 源站打印
尝试让客户在源站侧加一下打印,将收到的请求头打印出来,从源站的打印来看,出问题的时候的确是没有收到Upgrade: websocket头。而如果是正常的请求,源站是能打印出Upgrade: websocket头的。如果尝试在源站侧去掉这个Upgrade的校验,虽然可以请求成功,但是无法进行WebSocket通信,因为整条链路并不是走的WebSocket。
3. 排查CDN日志
排查后台CDN的日志,发现正常请求的hit_info字段显示的是WS,也就是走的WebSocket请求。而异常请求的hit_info字段是dynamic,也就是走的动态加速,并不是WebSocket。从现象分析来看,怀疑是L1收到的请求里就没有Upgrade: websocket相关的头,所以L1认为这不是WebSocket请求,走的是普通的动态加速,转发回源站也不会带Upgrade头。
4. DCDN侧增加debug日志
由于日志里并没有记录收到的客户端Upgrade字段,因此需要后台加一下debug日志,打印下该字段。
5. 重新复现问题
重新让客户复现了一次问题,并提供客户端抓包数据。从抓包数据看,客户端请求确实带了Upgrade头,而从DCDN的日志来看,确实是没有收到Upgrade头的,因此走的也是普通动态加速请求。同时从客户端收到的来自DCDN的报文看,这个TTL是64,这明显是不正常的。正常情况由于DCDN节点发出的报文TTL原始值是64,中间每经过一个网络路由节点,TTL减1,客户端收到的报文TTL不应该是64。因此判断是客户端存在劫持行为,走了代理,应该是客户端发出请求以后客户端层面做了异常转发,按照普通的HTTP请求转发,没有转WebSocket相关头导致的。
问题解决
配置HTTPS证书,客户端走wss请求以后,客户侧能复现问题的现场就正常了,无法再复现问题,而且线上错误率明显改善。
适用产品
DCDN