基于nginx-rtmp-module模块实现的HTTP-FLV直播模块nginx-http-flv-module(三)

12 篇文章 5 订阅
12 篇文章 6 订阅

        接上一篇《基于nginx-rtmp-module模块实现的HTTP-FLV直播模块nginx-http-flv-module(二)》内容。

        项目地址:https://github.com/winshining/nginx-http-flv-module,欢迎大家下载测试,返回bug和提交PR。

        项目演示视频:使用nginx-http-flv-module搭建简易直播环境

2018-10-28:现在nginx-htt-flv-module还有一个问题,多进程模式下,接收到publish的进程auto_push到另外的进程时,如果配置里存在多个server块,当请求的是非第一个server块时,可能造成播放失败,这是因为auto_push依靠unix domain socket通信,但是unix domain socket没有端口信息,所以,当播放和发布在不同的进程上时,由于auto_push无法判断查找的是哪个server块(默认是第一个),播放会失败。单进程没有这个问题,因为单进程没有auto_push,多进程模式下,只有一个server块配置时也没有问题。

2019-06-24:上述的问题已经解决,详情见高性能流媒体服务器nginx-http-live-module

2018-08-08更新:

        有网友反馈HTTP-FLV方式播放不能使用exec_pull,究其原因是因为HTTP-FLV请求首先都会通过ngx_http_flv_live_module的检查,才能继续往后边的流程执行(这个我一直在考虑怎么把它的执行次序调整到后边),但是在这儿没有针对exec_pull处理的逻辑,所以直接“找不到流”了,现在已经修复,但是逻辑很粗糙,凑合先用着。

2018-08-15更新:

        将压力测试程序和服务器分开在不同的服务器上进行压力测试时,发现如果服务器之间的网络带宽不够大,停止压力测试很可能造成服务器的CPU使用率为100%,原来遇到过类似的问题,是由于两次释放内存链表导致形成了链表环。修改后的代码在多次压力测试后未发现该问题(之前压测稳定后停止播放,平均不到10次,有时候4次就会复现),后续可能还需要更多的测试来验证。

2018-08-23更新:

        修复一个上次更新引入的新的bug,多次释放链表造成形成了链表环。另外更新了示例截图,分别是用JW Player,VLC和flv.js做的测试截图。

2018-09-14更新:

        修复GOP缓存模块中因为满足一定条件后释放内存池,后续再分配内存时造成崩溃的bug。这个bug是几天前有个厂商反馈的,nginx运行一段时间后会崩溃,但不是必现的,后调试产生的两个core文件发现都在同一个地方崩溃。

2018-09-22更新:

        有网友反馈使用on_connect和on_play回调命令时,有时请求会耗费很长时间才收到响应,并且Nginx的吞吐量在这期间下降很快,可能是这两个命令有什么问题,跟踪一段时间后还是找不到原因。后来在nginx-rtmp-module的pull requests中找到原因,如果在on_connect和on_play中使用了域名,nginx-http-flv-module会去解析域名,并且解析域名的接口是阻塞的。Nginx作为异步非阻塞的服务器,如果阻塞在域名解析接口上了,肯定就会导致吞吐量下降。现添加了一个配置项notify_no_resolve,默认是开启的,即不解析域名,这就要求默认情况下使用on_connect等命令时url中不能用域名,除非能保证域名解析很快,才能使用notify_no_reslove off;。但是有些网站是不接受纯IP地址访问的,所以这种情况需要用户自己根据实际情况做取舍了。

2018-09-29更新:

        有网友提交了一个PR,解决了一个比较隐蔽的bug,详情见pull request #73,在GOP缓存模块中,缓存链表头等变量空间使用了独立的内存池,在关闭连接时,先释放了这个内存池,再回收缓存链表时,再引用这些链表头就会崩溃。

2018-10-08更新:

        有网友在国庆节之前反馈了一个bug,详情见issue #72,之前一直没找到原因,现在修复了,auth_request验证会用到upstream,upstream发送信息给服务器时,会使得下游连接变得active,从而在后续的过程中一直进入不了发送函数。

2018-10-10更新:

        有网友反馈在ngx_rtmp_init_session中存在初始化失败后不会释放已经分配的内存池的问题,经提醒,发现ngx_http_flv_live_init_session中也有同样的问题,一并修复了。不过这个问题几乎不可能发生,在内存耗尽的情况下才可能出现。

2018-10-18更新:

        发现一个可能引起崩溃的bug,不过到现在为止还没有人反馈过这个问题,relay模块中的ngx_rtmp_relay_close函数,在发布端断开连接后,会将与它关联的订阅者逐个关闭,这些订阅者的连接的context是用一个链表链在一起的,关闭一个连接后会通过next指针找到下一个连接的context。关闭连接后会销毁内存池,而这个context是这个内存池中的一个对象,内存池销毁后,如果这块内存没被重新分配,那么侥幸还能获取它的next指针,如果这块内存已经被重新分配,那么这个context就已经无效了,访问就会崩溃。现改为关闭连接之前,先获取下一个context,存在一个临时变量中,再关闭连接,这样就避免了循环时依赖可能已经无效的context的next指针了。

2018-11-02更新:

        nginx-rtmp-module对纯音频支持有瑕疵,当开启wait_video或者wait_key时,无法播放,因为一直试图等待视频数据,nginx-http-flv-module修复了此问题。

2018-11-09更新:

        有网友反馈使用比较低版本(1.8.x)的Nginx编译会出现错误(至于为什么还用这么低版本的Nginx我不太清楚),经测试还不只一处有兼容性的问题,一并都修复了。

2018-11-12更新:

        一个厂商反馈json格式的stat解析有问题,100%复现,与我自己推流的比较发现,其推流的audio解析信息缺失,导致双引号缺失,解析错误,已经修复。

2018-11-22更新:

        有个网友反馈使用非常新的gcc(8.2.0)版本编译nginx-http-flv-module会失败,见issue #82,已修复。注意,gcc-8.2.0编译版本1.15.x以下的Nginx也会失败。

2019-01-05记录:

        不是更新,只是记录:)早就有重构模块调用顺序的想法,因为ngx_http_flv_live_module现在是请求“见到”的第一个模块,很多本来应该由后续模块处理的逻辑可能因为某些原因被ngx_http_flv_live_module“放弃”掉了,尽管这个请求本来在后续的模块看来是合法的。例如处理回调的模块ngx_rtmp_notify_module现在位于ngx_http_flv_live_module后面,后者本来不用关心前者处理的细节,但是现在由于模块的位置关系,使得ngx_http_flv_live_module要介入它后面的模块的一些处理细节,使得它的处理逻辑很复杂又不易被理解。这段时间正在将ngx_http_flv_live_module放到一个合适的位置,涉及的代码比较多,需要一段时间,修改完后会merge到master分支上。

2019-02-02更新:

        很久没有更新了,春节前最后一次更新。最近几天有网友反馈on_update在使用HTTP-FLV方式播放时有问题,见issue #85,一直无法复现,后来将on_play和on_play_done加上才复现了崩溃。原因有点莫名其妙,大概意思是ngx_rtmp_netcall_module中一个指针置为NULL了,但是调用ngx_rtmp_netcall_disconnect时这个指针却不是NULL,而是0x0A,调试了大半天都没找到原因,确定这个指针不是在已销毁的内存池中,加了个计数,计数为0时再置为NULL;另外,on_update也确实有问题,nginx-rtmp-module把ngx_rtmp_session_t结构体指针挂在结构体ngx_connection_t的data指针上,而Nginx原生的HTTP模块中是把ngx_http_request_t结构体指针挂在ngx_connection_t的data指针上的,所以执行ngx_rtmp_notify_update函数时,从data拿出来的数据是ngx_http_request_t指针,而不是ngx_rtmp_session_t指针,造成访问一些数据会崩溃。测试暂时没有问题了,已更新代码。

2019-02-13更新:

        春节前一个美国网友反馈了一个bug,见issue #86。经过调试发现服务器监听IPv6地址时,如果客户端是IPv4地址,服务器接收到请求时,会将IPv4地址映射成为IPv6地址。但是如果HTTP模块监听的是IPv4地址,而RTMP模块监听的是IPv6地址,HTTP模块带过来的地址格式不会被映射成IPv6地址,造成比较协议族+端口+地址时失败。

2019-02-23记录:

        接2019-01-05记录,模块调用顺序已经调整好,已经合并到master分支,简单测试没发现问题,欢迎试用并反馈问题。

2019-03-14更新:

        修复了JSON风格的stat解析错误问题,感谢网友的PR。发布版本1.2.6,欢迎测试并反馈问题。

2019-04-23更新:

        之前测试HTT-FLV的客户端(VLC或者flv.js)使用的HTTP协议一直都是HTTP/1.1,后来有网友反馈回复的数据老是有问题,见issue #99(但并不是标题所说的原因),每次回复FLV头时总是多一些数据,查看了一下是chunked结构,但是一直没复现出来。直到昨晚使用curl并且指定--http1.0选项,发现发送的数据是chunked结构,但是Transfer-Encoding: chunked这个HTTP头是HTTP/1.1引入的,HTTP/1.0并不支持,之前没有区分HTTP/1.0和HTTP/1.1,也就是说客户端使用HTTP/1.0协议,服务器只要配置了chunked_transfer_encoding on;,就会回复chunked数据,而没有考虑协议版本的问题,造成客户端不解析回复的数据,直接存储了。问题已经修复。网友反馈的情况是:

flv.js<--Nginx(HTTPS proxy)<--Nginx(HTTP-FLV)<--Nginx(RTMP)<--RTMP(publish)

出现这个问题的原因应该是proxy和后端的服务器之间使用的是HTTP/1.0协议。

2019-05-07更新:

        有网友反馈使用HTTP-FLV时,播放器无法解析metadata,但是视频是可以播放的,用wget或者curl下载播放链接并保存为文件,二进制打开后发现metadata似乎多了一些数据,跟RTMP播放抓包的数据对比发现没有差异,好久才回过神来RTMP播放抓的包里是完整的RTMP数据包,也就是说除了metadata以外,还有RTMP的basic header,chunk message header,这两部分在HTTP-FLV播放时是不应该发送给客户端的,最新的代码已经去掉并验证通过(RTMP和HTTP-FLV)。隐约想起来去年就有网友反馈使用flv.js播放时,会出现不能解析的AMF格式的错误,当时没引起重视,应该就是这个错误,使用flv.js测试也没问题了。

2019-05-28更新:

        有网友反馈停止播放(HTTP-FLV)后,查看stat,会有连接信息,但是#client一列显示为0,输入速率和输出速率也是0。让添加“drop_idle_publisher”配置后,反馈还是存在相同的问题。经查是允许还没有publisher的时候发起播放请求(等待publisher接入),关闭播放请求后,原来清除连接数据的逻辑是在另一个地方调用的,但是因为有些条件并不会执行到那儿去。现修改为关闭播放时如果没有publisher,直接提前清除数据。

2019-07-07更新:

        前段时间有个网友反馈推流一段时间后,然后再播放流的时间戳(RTMP/HTTP-FLV)不是从0开始的,现已修改为从0开始。

2019-08-01更新:

        修复了nginx-rtmp-module的issue列表里1249号issue提出的问题,见Recording filename sometimes missing stream name #1249

2019-08-11更新:

        nginx-rtmp-module不支持VHOST功能,所以stat.xsl也不支持VHOST功能,导致访问stat时,某些场景下不能正常工作,例如分别向监听端口为1935和1985的两个虚拟主机(对应两个不同的server配置)推两个同名的流,然后访问stat,由于原来的stat.xsl的onclick通过getElementById获取的节点id是流名称标识的,会出现点击1985的虚拟主机的推流详情,无反应,而展开的是1935的虚拟主机的推流详情的问题,所以需要更多的信息来区分节点id,目前已修复该问题。

2019-08-13更新:

        有网友反馈使用HTTP-FLV方式播放时,第二个播放连接会卡住,测试很容易复现,花了大半天才基本上理清了问题根源,这个bug是由2019-07-07添加的代码引入的,究其原因是publisher的数据拷贝只有一份,然后这份拷贝会被发送给不同的player,但是不同的player的接入时间不一样,所以要求不同的player的时间戳都从0开始,那么每个player都需要有个自己的偏移时间戳。但是由于只有一份内存拷贝,接收到新的播放请求后,会将后接入player的时间戳修改为0,造成前一个player接收到这一份数据的时间戳为0,所以会卡住。现在修改为在每个player在发送时校正时间戳。

2019-08-24更新:

        今天使用gcc asan(gcc-4.8.x以上自带)检查nginx-http-flv-module是否有内存泄露和内存访问越界的问题,没想到还真找到两只bug,都是heap-use-after-free类型的bug,即访问已经释放了的内存池中的内存,主要原因是Nginx在表示传输层连接的结构体和表示应用层HTTP请求的结构体中有两个不同的内存池,关闭HTTP连接时,首先释放HTTP请求的结构体中的内存池,再释放传输层连接的结构体中的内存池,问题就出在释放HTTP请求的结构体中的内存池后,有两个地方还对其中的一些数据有引用。在内存使用量不紧张时这种情况是没有问题的,被释放的内存池不会被马上分配给其他地方使用,但是内存使用量紧张时,可能释放的内存池会被马上再分配,轻则数据不对,造成运行逻辑不正确,重则导致进程崩溃。现已修改为分配内存都使用传输层连接的结构体中的内存池,暂时没再发现同样的问题。

2019-09-11更新:

        一个网友反馈Nginx偶尔会崩溃,但是没打开生成core文件的配置,dmesg查看只有如下信息:

[7253350.670459] nginx[1596]: segfault at 0 ip 00007f1d1a9f7b44 sp 00007ffc5b4764f0 error 4 in ngx_http_flv_live_module.so[7f1d1a9e2000+5a000]

网上查了一下,error 4表示用户态读内存操作越界,又根据ip所指的地址和ngx_http_flv_live_module.so的基址的差值,objdump -tT看一下ngx_http_flv_live_module.so里的函数地址,大概能定位是ngx_rtmp_append_shared_bufs有问题,应该是最后一个参数为空导致的,但是没有堆栈信息,无法知道上下文,所以不知道是哪个地方出了问题。后来在服务器上开启生成core文件的配置,等待了一天左右,产生core文件了。gdb调试core文件,bt一查看,确定了是给客户端发送meta的时候,由于meta是空的,导致崩溃。然后一边反馈给网友推流器没有上传meta信息,一边加固模块,后续测试打印出没有meta的日志,问题解决,代码已经更新。

2019-09-23更新:

        有网友反馈推RTMPS流,经过stunnel转换成RTMP后推到nginx-http-flv-module会失败,见#127,调试了一下,是由于终端传递的tcUrl是以rtmps://开头的,而nginx-http-flv-module不支持RTMPS的schema,所以解析错误。现在兼容了这种情况。另外,如果要原生支持RTMPS,可以使用nginx-http-live-module,见高性能流媒体服务器nginx-http-live-module,之前一直找不到压力测试nginx-http-live-module的RTMPS的方法,无法保证RTMPS功能在高并发环境下是否能正常运行。受此问题的启发,查了下stunnel的用法,支持RTMPS->stunnel->RTMP,反之也支持。压测nginx-http-live-module的RTMPS表示没有问题,对RTMPS的原生支持比RTMP经过stunnel转换成RTMPS的效率应该高不少。注:nginx-http-live-module没有开源。

2020-01-02更新:

      已经有段时间没有收到bug反馈了,2019年的倒数第二天收到一个bug反馈,以多进程模式运行Nginx,且系统支持SO_REUSEPORT选项,在rtmp配置块中的listen配置项目后添加reuseport,会导致播放失败。由于nginx-http-flv-module只部分解决了在多进程模式下VHOST的问题,加之我自己的操作系统不支持SO_REUSEPORT,所以之前测试一直都是以单进程模式运行Nginx,没有发现该bug。现已修复,reuseport主要是解决惊群的问题,由内核把请求平均分配给Nginx的多个进程,所以顺带解决了负载不均衡的问题。

2020-01-11更新:

      偶然发现开启gop_cache和interleave(默认音视频是通过两个“通道”传输,开启此选项后,音视频在一个“通道”中交错传输)选项后,用flv.js不能播放,vlc播放(rtmp和http-flv)卡顿,关闭gop_cache或者interleave或者二者都关闭后又都正常。查看打印日志时间戳等信息都没有问题,对比gop_cache和rtmp_live两个模块中的处理,才发现开启interleave后,需要先后发送视频codec数据和音频codec数据(就是sps,pps等信息),而gop_cache没有处理interleave的情况,导致每次只会传输视频codec数据或者音频codec数据,造成播放器无法正确初始化。参考rtmp_live的做法,修改后播放正常。

2020-02-08更新:

      今天是元宵节,祝元宵节快乐!另外,武汉加油,中国加油!

      2019-08-01更新中修复了nginx-rtmp-module的#1249 bug,但是经网友反馈,当Nginx以多进程方式运行,录制设置为手动时,且推流器是OBS时,发送录制命令后会产生重复的录制文件(必现,但是推流器是FFmpeg却没问题)。现已修复。

2020-03-04更新:

      昨天有网友提交PR,见#150,称用ASAN检测到内存泄露,看了下修改的地方,的确在Nginx退出时不会释放创建的内存池。奇怪的是从去年8月份起,每次修改代码也启用了ASAN,只检查出两个heap-use-after-free问题,却没有收到过内存泄露报告,可能是编译器版本较低导致的。现已修复,测试已没有问题。

2020-03-16更新:

      有网友提交PR,见#152,解决了使用on_publish回调返回302 rewrite流的名称时,HLS(其实DASH也有相同的问题)的playlist名称不会被修改为已经rewrite的流名称,该PR只修改了config文件里ngx_rtmp_notify_module的顺序,没涉及到源代码的修改,目前测试暂时没有问题。nginx-rtmp-module也有这个问题,该网友也提交PR给nginx-rtmp-module,但是鉴于Arut已经不维护nginx-rtmp-module了,该PR大概率不会被合并了。

2020-04-21更新:

        有网友反馈在源服务器和边缘服务器上都指定"meta copy;"时,边缘服务器无法播放RTMP流,源服务器播放正常,这个问题似乎很早之前就有人给nginx-rtmp-module的作者反馈过,但是一直没回复。Debug发现在边缘服务器上收到的meta信息里少了一个字符串信息"onMetaData",是在前面的codec中解析时,移动了一个偏移量把它排除了,造成客户端无法解析。

2020-04-25更新:

        有网友(好像是个大佬,OpenResty的核心开发者之一)反馈某些情况下存在内存泄露的问题,见#159。原因我在该issue下也已经说明,是GOP缓存模块里的一个内存泄露问题,已经修复。

2020-05-02更新:

        修复在Windows上编译(编译器VS 2013)的bug。

2020-06-21更新:

        修复一个潜在的栈溢出bug,见#170

2020-07-11更新:

        录制的信息可以在stat里面看到了,如下图所示:

stat里的录制信息

2020-07-31更新:

        修复一个在某些很新的Linux发行版上遇到的编译错误(因为使用了很新的编译器能检查出来),见#174

2021-04-04更新:

        修复一个在类Unix系统上,将nginx-http-flv-module编译为动态模块,Nginx开启多个worker进程,relay会失败的bug,这个bug在nginx-rtmp-module中就存在。

2021-08-14更新:

        有网友反馈将nginx-http-flv-module配置为relay服务器时,push会失败,见#211,跟踪了一下代码,是因为配置的push后的url中有$,即有变量,所以重新解析url,导致已解析的地址数组出线问题,问题已修复。

2021-12-31更新:

        最近忙工作,基本没时间维护nginx-http-flv-module,此次修复了一个在stat页面偶尔会出现已销毁流的信息的bug,见#181,确认是之前某个bug修复引入的问题。

其他文章:

基于nginx-rtmp-module模块实现的HTTP-FLV直播模块nginx-http-flv-module(一)

基于nginx-rtmp-module模块实现的HTTP-FLV直播模块nginx-http-flv-module(二)

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 21
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值