记一次丢包分析

2020-12-21 11:37:10 浏览数 (1)

最近笔者在做视频通话相关业务,在分析一些花屏、卡顿等视频异常现象时,首先想到的就是抓包,于是笔者使用了tcpdump进行了抓包,命令如下:

代码语言:javascript复制
tcpdump -i any -w rtp.pcap

使用wireshark打开包分析RTP流如下:

笔者当场就吃惊了,明明局域网内通信,为何视频有10%的丢包。

于是笔者赶紧一波Google操作,搜索到的原因无外乎以下几种:

  • 防火墙
  • UDP buffer size不足
  • 系统负载过高
  • 应用内丢包

首先可以排除掉第一种和第三种,由于是在本机虚拟机测试,防火墙肯定全关,系统负载也查看了,确定不高。

然后笔者首先验证的是第四种,应用内丢包。这里先说一下笔者的测试场景: 192.168.0.103FreeSWITCHip192.168.0.102是软电话的ipFreeSWITCH先呼叫软电话,软电话接通后,FreeSWITCH再呼叫自己,然后播放一个mp4(FreeSWITCH呼叫自己是业务需要)。命令如下:

代码语言:javascript复制
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不足”这个原因比较可疑了。于是笔者立马修改了内核的缓存大小:

代码语言:javascript复制
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提供了设置缓存区大小的参数,例如:

代码语言:javascript复制
tcpdump -i any --buffer-size=409600 -w rtp.pcap

buffer-size的单位是KB,所以上述参数设置了400MB大小的缓存。

有些老版本的tcpdump可以使用-B 409600来设置缓冲区大小。

经过测试,wireshark确实没有“丢包”了。

tcpdump默认的buffer大小为2MB,这对于抓取视频包来说远远不够,因此,加上-B很有必要。

0 人点赞