最近笔者在做视频通话相关业务,在分析一些花屏、卡顿等视频异常现象时,首先想到的就是抓包,于是笔者使用了tcpdump
进行了抓包,命令如下:
tcpdump -i any -w rtp.pcap
使用wireshark
打开包分析RTP
流如下:
笔者当场就吃惊了,明明局域网内通信,为何视频有10%
的丢包。
于是笔者赶紧一波Google
操作,搜索到的原因无外乎以下几种:
- 防火墙
UDP buffer size
不足- 系统负载过高
- 应用内丢包
首先可以排除掉第一种和第三种,由于是在本机虚拟机测试,防火墙肯定全关,系统负载也查看了,确定不高。
然后笔者首先验证的是第四种,应用内丢包。这里先说一下笔者的测试场景:
192.168.0.103
是FreeSWITCH
的ip
。192.168.0.102
是软电话的ip
。FreeSWITCH
先呼叫软电话,软电话接通后,FreeSWITCH
再呼叫自己,然后播放一个mp4
(FreeSWITCH
呼叫自己是业务需要)。命令如下:
originate user/1005 &bridge(sofia/internal/9196@192.168.0.103:5060)
路由如下:
代码语言:javascript复制<extension name="echo">
<condition field="destination_number" expression="^9196$">
<action application="answer" />
<action application="endless_playback" data="/root/test.mp4"/>
</condition>
</extension>
从wireshark
分析中可以看出,103
发给103
有比较大的丢包。这个比较好测试,既然tcpdump
没有抓到FreeSWITCH
发出去的包,那我只需要验证一下FreeSWITCH
到底有没有发出去,就可以确定是不是应用内丢包了。
于是,笔者在通话开始以后,使用uuid_debug_media xxxxx vwrite on
打开媒体发送统计,将日志与tcpdump
的抓包序号做了对比。
很明显,FreeSWITCH
已经将包发出了,但是抓包中却没有。可以排除应用内丢包了。
分析到这里,貌似只有“UDP buffer size
不足”这个原因比较可疑了。于是笔者立马修改了内核的缓存大小:
sysctl -w net.core.rmem_default=16777216
sysctl -w net.core.wmem_default=16777216
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
经过测试,丢包依然存在。
分析到这里,笔者开始怀疑,是不是通话根本没有丢包,但是tcpdump
由于自己的原因没有抓到包,因此“显示的丢包”。
不知道大家在抓包结束后,有没有观察过tcpdump
的输出。反正笔者是从来没有注意过。这里笔者需要自我批评,如果笔者早注意到,也不会花费两天的时间解决这个问题。看来细心真的很重要。:-)
从字面意思看,有1503个包被内核丢弃了,为何大量的包被内核丢弃呢?
从这里 https://unix.stackexchange.com/questions/144794/why-would-the-kernel-drop-packets (可点击『阅读原文』查看)我们可以找到一些答案。
原来,tcpdump
在捕获到网络接口的原始数据包时,会先将包放在一个缓冲区中,然后,从这个缓冲区中读取包进行解析,当tcpdump
解析的慢时,就会造成缓冲区溢出,因此包被丢了。
tcpdump
提供了设置缓存区大小的参数,例如:
tcpdump -i any --buffer-size=409600 -w rtp.pcap
buffer-size
的单位是KB,所以上述参数设置了400MB大小的缓存。
有些老版本的tcpdump
可以使用-B 409600
来设置缓冲区大小。
经过测试,wireshark
确实没有“丢包”了。
tcpdump
默认的buffer
大小为2MB,这对于抓取视频包来说远远不够,因此,加上-B
很有必要。