在实战中使用nginx-rtmp遇到的TCP连接问题分析

背景

前段时间公司做了一次体育赛事的现场直播,网络由某通信公司负责搭建,主要测试5G CPE上行网络的带宽和稳定性,为了做到万无一失,他们同时搭建了一条用作备份的400M光纤线路。通过配置交换机来做到主备切换,要达到以下的效果:

  • 无线链路down掉,交换机自动检测到丢包,丢包到指定数量(可以在交换机中配置),自动切换到备用链路。
  • 无线链接恢复,备用链路切换回无线链路。

参考 静态路由与SLA技术

我们采用nginx-rtmp搭建了2层CDN。

测试

推流端推送RTMP流会向nginx-rtmp发送请求建立TCP链接,推流过程中,把交换机上的无线链路网线拔掉。自动切换到光纤线路,推流端重连后依然不能够成功建立链接,推流软件卡死。

server端的TCP链接一直存在:

root@iz2zehy7gff0ksipgb4ch3z /u/l/nginx# netstat -natp | grep "1936"
tcp 0 0 0.0.0.0:1936 0.0.0.0:* LISTEN 9467/nginx: master
tcp 0 0 192.168.199.6:1936 223.71.3.82:46012 ESTABLISHED 11177/nginx: worker

nginx 报错了:

2019/05/20 15:44:58 [error] 6947#0: *286 live: already publishing, client: 223.71.3.82, server: 0.0.0.0:1936

此时

就是因为无线链接断开时,TCP链接不能够被正常关闭,publisher会一直存在导致的。

复习一下四次挥手:

我们知道TCP连接有一个特性:

TCP 连接一旦建立,只要通信双方之间的中间结点(包括网关和交换机、路由器等网络设备)工作正常,那么在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。TCP 连接的这种特性,使得一个长期不交换任何信息的空闲连接可以长期保持数小时、数天甚至数月。中间路由器可以崩溃、重启,网线可以被挂断再连通,只要两端的主机没有被重启,TCP 连接就可以被一直保持下来。

可以看到,网线虽然断掉了,但是server端没有收到client的任何消息,server端不会主动发起挥手,因此连接会一直维持很长一段时间(我的测试机器上大概数小时)。链接断开后server端一直在发送PSH+ACK:

如何才能实现快速重连

为源站加load balance

加一个备源和一个调度服务,调度策略采取轮询,两次连续的TCP连接请求会被定向到不同的源站上面。这个方法治标不治本,切一次可以,如果无线链路恢复,再切回来的时候,可能TCP链接还没有关闭。

添加drop_idle_publisher

Syntax: drop_idle_publisher timeout

Context: rtmp, server, application

Drop publisher connection which has been idle (no audio/video data) within specified time. Default is off. Note this only works when connection is in publish mode (after sending publish command).

drop_idle_publisher 10s;

nginx-rtmp会在指定的时间内丢弃空闲的publisher:

root@iz2zehy7gff0ksipgb4ch3z /u/l/n/logs# netstat -natp | grep "1936"
tcp 0 0 0.0.0.0:1936 0.0.0.0:* LISTEN 11421/nginx: master
tcp 0 0 192.168.199.6:1936 61.148.243.150:9338 ESTABLISHED 12923/nginx: worker
tcp 0 1 192.168.199.6:1936 223.71.3.82:47240 FIN_WAIT1 -

我们将drop_idle_publisher设置为2s,抓包可见这次是server端在2s后探测到这个TCP连接处于空闲状态,主动发起了挥手消息,此时publisher就被释放掉了,再次推流会重新建立新的TCP,重新生成此publisher。

上图是链路断掉后,TCP链接完全断开前server端向client发送的数据包,可以看到一直在发送FIN+最后一个数据包的ACK,时间间隔大概为 0.2秒->0.4秒->0.8秒->1.6秒->3.2秒->6.4秒->12.8秒->25.6秒

这种方法是可行的。

so_keepalive

listen

syntax: listen (addr[:port]|port|unix:path) [bind] [ipv6only=on|off] [so_keepalive=on|off|keepidle:keepintvl:keepcnt|proxy_protocol]

context: server

Adds listening socket to NGINX for accepting RTMP connections

关于TCP探活机制的几个参数的说明:

  • keepcnt 关闭一个非活跃连接之前进行探测的最大次数t
  • keepidle 对一个连接进行有效性探测之前运行的最大非活跃时间间隔
  • keepintvl 两个探测的时间间隔

设置如下参数:

listen 1936 so_keepalive=5s:2:2;

可以看到,最后一个ACK没有回复后隔了5秒开始TCP keep-alive 探活,总共两次,间隔2秒,最后发送RST+ACK断开了TCP连接 。

参考

nginx-rtmp-module wiki

TCP 连接断连问题剖析

在实战中使用nginx-rtmp遇到的TCP连接问题分析的更多相关文章

  1. Ubuntu中使用Nginx+rtmp搭建流媒体直播服务

    一.背景 本篇文章是继上一篇文章<Ubuntu中使用Nginx+rtmp模块搭建流媒体视频点播服务>文章而写,在上一篇文章中我们搭建了一个点播服务器,在此基础上我们再搭建一个直播服务器, ...

  2. Ubuntu中使用Nginx+rtmp模块搭建流媒体视频点播服务

    1. 背景 不知不觉笔者来到流媒体部门已经一年半多了,积攒了不少的流媒体知识,但平时工作也比较忙,很少进行总结性的梳理,最近准备花几个周末时间写一个流媒体系列的实践文章,也算是给自己做总结的同时帮助有 ...

  3. linux中top命令使用及查看tcp连接

    Linux top命令 介绍:top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,Linux top命令用于实时显示 process 的动态,即可以通过用户按键来不断 ...

  4. Centos7 搭建Nginx+rtmp+hls直播推流服务器

    1 准备工具 使用yum安装git [root~]# yum -y install git 下载nginx-rtmp-module,官方github地址 // 通过git clone 的方式下载到服务 ...

  5. TCP连接中的状态

    1. 正常状态转换 我们用图 3-13 来显示在正常的 TCP 连接的建立与终止过程中,客户与服务器所经历的不同状态.读者可以对照图 3-12 来阅读,使用图 3-12 的状态图来跟踪图 3-13 的 ...

  6. Android中直播视频技术探究之---视频直播服务端环境搭建(Nginx+RTMP)

    一.前言 前面介绍了Android中视频直播中的一个重要类ByteBuffer,不了解的同学可以 点击查看 到这里开始,我们开始动手开发了,因为我们后续肯定是需要直播视频功能,然后把视频推流到服务端, ...

  7. [微信小程序直播平台开发]___(二)Nginx+rtmp在Windows中的搭建

    1.一个可以忽略的前言 Nginx (engine x) 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Ramble ...

  8. 转:Nginx RTMP 功能研究

    看点: 1.    Nginx 配置信息与使用.  (支持 rtmp与HLS配置) 2.    有ffmpeg 编译与使用,    命令行方式来测试验证客户端使用. 转自:http://blog.cs ...

  9. centos7+nginx+rtmp+ffmpeg搭建流媒体服务器(保存流目录与http目录不要随意配置,否则有权限问题)

    搭建nginx-http-flv-module升级代替rtmp模块,详情:https://github.com/winshining/nginx-http-flv-module/blob/master ...

随机推荐

  1. 简单的HTML5音乐播放器(带歌词滚动)

      // // 0) { this.lrcArr.push(item); } } frag = document.createDocumentFragment(); for(i = 0,len = t ...

  2. erlang实现DNS解析域名

    erlang的DNS解析,有个inet模块,可以做这个事情,对应的api如下:(这里用的R16B的版本) inet:getaddr/2解析对应一个ip,而inet:getaddr/2解析有可能对应1个 ...

  3. 05 referer头与防盗链

    像上图中的这个效果,当我们在网页里引用站外图片时,常出现这样的情况. ??? 服务器是怎么样知道,这个图片是在站外被引用的呢? 还有在网站的统计结果,统计用户从何而来,如下图 ??? 统计时,是如何得 ...

  4. POJ 1195 Mobile phones (二维树状数组)

    Description Suppose that the fourth generation mobile phone base stations in the Tampere area operat ...

  5. poj 1286 Necklace of Beads poj 2409 Let it Bead HDU 3923 Invoker <组合数学>

    链接:http://poj.org/problem?id=1286 http://poj.org/problem?id=2409 #include <cstdio> #include &l ...

  6. find命令用法

    关于查找 文件查找:     locate非实时查找:根据索引查找     find实时查找:根据文件的各种属性去找到相对应文件     根据文件的各种属性去找到相对应文件 文本搜索:     gre ...

  7. windows下使用ofstream默认输出内存数据到文件中时,会自动将0A换成0A0D

    0A即\n,而0D是\r,windows下换行是\n\r,因此会自动转换. 但是,这样会带来很大的问题,导致由内存写入文件中的数据和内存中不一样,还不知道是什么原因造成的. 特别是将从网络接收来的pn ...

  8. 在给mysql数据库备份时,报错: mysqldump: Got error: 145: Table '.\shengdaxcom\pre_forum_thread' is marked as c rashed and should be repaired when using LOCK TABLES

    在给mysql数据库备份时,报错: mysqldump: Got error: 145: Table '.\shengdaxcom\pre_forum_thread' is marked as cra ...

  9. linux环境下安装的activemq的输出日志

    activemq输出日志的位置: activemq/data/activemq.log 查看activemq.log文件即可.

  10. 在c中break的使用

    break语句通常用在循环语句和开关语句中.当break用于开关语句switch中时,可使程序跳出switch而执行switch以后的语句:如果没有break语句,则会从满足条件的地方(即与switc ...