前段时间公司作了一次体育赛事的现场直播,网络由某通讯公司负责搭建,主要测试5G CPE上行网络的带宽和稳定性,为了作到万无一失,他们同时搭建了一条用做备份的400M光纤线路。经过配置交换机来作到主备切换,要达到如下的效果:html
参考 静态路由与SLA技术nginx
咱们采用nginx-rtmp搭建了2层CDN。git
推流端推送RTMP流会向nginx-rtmp发送请求创建TCP连接,推流过程当中,把交换机上的无线链路网线拔掉。自动切换到光纤线路,推流端重连后依然不可以成功创建连接,推流软件卡死。github
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 报错了:app
2019/05/20 15:44:58 [error] 6947#0: *286 live: already publishing, client: 223.71.3.82, server: 0.0.0.0:1936
此时socket
就是由于无线连接断开时,TCP连接不可以被正常关闭,publisher会一直存在致使的。tcp
复习一下四次挥手:ide
咱们知道TCP链接有一个特性:测试
TCP 链接一旦创建,只要通讯双方之间的中间结点(包括网关和交换机、路由器等网络设备)工做正常,那么在通讯双方中的任何一方主动关闭链接以前,TCP 链接都将被一直保持下去。TCP 链接的这种特性,使得一个长期不交换任何信息的空闲链接能够长期保持数小时、数天甚至数月。中间路由器能够崩溃、重启,网线能够被挂断再连通,只要两端的主机没有被重启,TCP 链接就能够被一直保持下来。
能够看到,网线虽然断掉了,可是server端没有收到client的任何消息,server端不会主动发起挥手,所以链接会一直维持很长一段时间(个人测试机器上大概数小时)。连接断开后server端一直在发送PSH+ACK:
加一个备源和一个调度服务,调度策略采起轮询,两次连续的TCP链接请求会被定向到不一样的源站上面。这个方法治标不治本,切一次能够,若是无线链路恢复,再切回来的时候,可能TCP连接尚未关闭。
Syntax: drop_idle_publisher timeout
Context: rtmp, server, applicationDrop 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秒
这种方法是可行的。
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探活机制的几个参数的说明:
设置以下参数:
listen 1936 so_keepalive=5s:2:2;
能够看到,最后一个ACK没有回复后隔了5秒开始TCP keep-alive 探活,总共两次,间隔2秒,最后发送RST+ACK断开了TCP链接 。