问题描述
用户的mp3视频存在在OSS上,使用ffplay播放的时候,播放途中会出现播放断开,报错如下
Error in the pull function. The specified session has been invalidated for some reason.
初步分析
1. 尝试复现
根据用户提供的mp3音频的URL,尝试在本地复现,发现测试播放一直正常,并没有出现用户说的播放中途断开的问题,而用户却几乎百分百必现该问题,因此怀疑还是客户端网络环境问题。
2. 传输加速正常
让用户尝试使用OSS的传输加速来播放,测试发现使用传输加速的地址去播放,就可以完整地播放完。根据以上测试,初步判断跟客户的网络环境有关。不过用户显然不认可这个结论,首先用户反馈同样把这个mp3音频放到另外一个云厂家,在同样的客户端上去播放就一切正常,这不得不怀疑这个问题可能还是跟OSS有关。其次使用OSS的传输加速是需要费用的,客户并不想为此买单。
3. 对比测试
让用户尝试直接用chrome浏览器播放或者用VLC播放器去播放,播放效果还可以,可以顺利播放完,但是用ffplay播放却一直有问题。这个测试的结论,似乎又推翻了上一个用传输加速测试的结果,因为同样的环境下用别的播放器却可以完整播放。同时,如果wget下载也是可以正常下载完,并不会存在断开的问题,由此分析这个问题还是跟播放器流式请求有关。
抓包分析-OSS
1. TCP ZeroWindow
为了更直观定位问题,尝试让用户用http去播放复现并提供一份抓包数据。通过过滤对应tcp流从下往上看,可以看到在19:21:48.605622时间点,NO1965包客户端因为接收窗口满了,Wireshark打了TCP ZeroWindow的标记,随后OSS发TCP Keep-Alive探测帧探测,直到19:21:59.621757时间点,NO1997包客户端重新更新接收窗口,Wireshark标记TCP Window Update,OSS才重新发送数据,中间间隔了11s,见下图3-1。同时看整个数据包,存在比较多的这种情况。
图3-1 TCP ZeroWindow
2. OSS发送了FIN
从NO2152包开始OSS继续发送数据给客户端,直到最后NO2177包OSS突然发送了一个FIN包断开了连接,通过更改Wireshark对于Time的显示格式发现从开始播放到OSS发了FIN包断开连接,整个过程才持续了100多苗,而整个音频有10分钟。这里从抓包的现象来看的确跟用户描述的现象一致,在播放的过程中停止播放了,而且从抓包结果来看还是因为OSS突然发了FIN包导致播放器断开连接,无法读取到新的视频Packet导致停止播放,见下图3-2
图3-2 OSS发送了FIN包
3. OSS单连接最低下载速度
以上现象看比较像一个OSS最低下载速度的限制,我们先来说下这个最低下载速度的理解。
一个正常C/S 架构的系统,通常会有很多Buffer,会设置很多超时时间,针对Tengine(OSS基于Tengine)会有send_timeout,recv_timeout,keepalive_timeout等各种超时限制。这就会造成系统会有一个最小下载速度的限制。以下是一份基于wget的 --limit-rate 功能进行二分测试得到的OSS最低下载速度的数据
单连接持续 5k 以内速度必然出问题(一般持续30s+出问题) 单连接持续 5 ~10k 以内速度随机出问题,看系统状况(比较具有偶然性) 单连接持续 10k+ 基本不出问题。
4. 分析下载速度
看抓包文件的Conversations信息,发现下载速率很低,132s才请求了1695KB的数据,平均速度也就差不多10KB/s的速度,见下图3-3
图3-3 分析下载速度
分析源文件mp3文件,大小是6559630Bytes,整个音频时长648s,见下图3-4。按照音频大小和音频时长可以计算得出平均每秒10123Bytes,略微大于10KB/s。但网络并不能保证每一秒的数据都一定大于10KB,在这个过程中有多次存在下载速度比较低的情况,低于OSS的最低下载速度,就会被OSS断掉连接,这也可以解释为什么OSS会突然发FIN包,同时也可以解释为何客户端一直出现TCP ZeroWindow的问题。OSS要高于这个最低下载速度发包,但播放速度以及码率限制了播放器缓冲区能够接收的数据,所以就会将下载速度降下来,多次之后就会出现后续OSS不再发送数据 。基于以上分析,要解决这个问题,需要给这个音频转码,提高码率以此来保证提高下载速度(因为播放时长是不可能缩短的)。文件不大的情况下也可以考虑一次性全读出来,放内存或者本地再慢慢处理。
图3-4 ffplay分析音频Duration时长信息
为什么使用传输加速正常
传输加速sndbuf 稍大,对于这个文件本身恰好没问题而已,换个大点的文件还是会有一样的问题,传输加速并不能从根本上解决这个问题。
为什么使用chrome播放正常
Chrome播放是通过range的形式去GET请求,需要多少数据就从服务器端RangeGet读多少,因此并不会产生这个最低下载速度的问题。
为什么我测试正常
我们的网络环境质量较好,因此在请求的过程中始终保持在10KB/s +的速度,并没有触发OSS的最低下载速度。而客户那边网络质量不佳,刚好到了这个临界点。
CDN加速架构
1. CDN加速也有问题
由于客户的业务就是需要ffplay流式读取播放,以上说的方案并不能满足用户需求。考虑到CDN加速OSS,客户端可以就近读取缓存,有更好的加速效果,用户尝试使用了CDN加速的方式来播放,但是问题依旧反复出现。
2. 抓包分析-CDN
抓了一份ffplay播放通过CDN加速的URL复现问题的包,发现也是存在CDN在发送数据的时候突然发送了FIN包,见下图NO2306包。由于CDN也是基于Tengine,看起来也是有跟OSS类似的问题。
3. 增加写客户端超时
由于CDN针对某一个域名是可以调整写客户端超时时间调整的,这个案例中可以加大写客户端超时时间,加大写客户端超时时间可以降低系统的最低下载速度,由此来解决这个问题。这个案例里,我们将用户的CDN域名的写客户端时间调整到900s(默认30s)以后,用户反馈可以完整的播放完mp3了。
适用于
- 对象存储OSS
- CDN