nginx-rtmp-module的缺陷分析

Arut最初在开发nginx-rtmp-module的时候只实现了单进程模式,好处是架构简单,推送和播放,数据统计,流媒体控制等都在一个进程上完成。可是这显然浪费了Nginx多进程(在Linux和FreeBSD平台上每一个进程均可以绑定一个CPU核心,以减小进程切换带来的开销)的处理能力。可是,若是开启多进程模式,推送和播放若是不在同一个进程上,会形成播放失败的问题:nginx

另外,请求数据统计信息也是个问题,由于采起HTTP方式请求数据统计信息时,在多进程模式下,请求被Nginx随机分配给了worker进程,可能形成我想看worker 1上的数据统计信息,可是Nginx返回的是worker 3上的数据统计信息。流媒体控制也采起了HTTP请求的方式,因此也存在着一样的问题:
git

针对推送和播放不在同一个进程上的问题,Arut后来加入了auto push的功能,即把原始的推流数据再relay到其余进程上去。这个功能须要Unix domain socket的支持(因此类Unix系统都支持,Windows在Windows 10的某个版本后才开始支持):
github

这样处理后,无论播放请求落在哪一个进程上,都能得到推送数据。服务器

对于后面两个问题,Arut给出了一个布丁,须要修改Nginx自己的源代码,详情见per-worker-listener。这样处理后,在HTTP请求时加上端口号信息,就能够指定请求某个进程上的数据统计信息了,流媒体控制相似:架构

在测试中发现auto push的并发性能并不能随着CPU个/核数的提升而提升,通常在400~500路后就没法再提高(笔记本测试)。是什么缘由呢?简单分析一下:假设服务器的CPU个/核数为N(Nginx的进程数通常配置为跟CPU个/核数相等),推流路数为M,且有M>>N,例如M=1000,N为4。假设M个推流请求被平均分配到N个进程上(其实是不会被绝对平均分配的,可是相差不会很大),那么每一个进程须要处理分配给本身自己的请求数为:并发

Publishers(self) = M / Ndom

另外,要保证某个播放请求无论被哪一个进程接受都能成功,那么每一个进程都要接受另外N-1个进程的auto push过来的流,即:socket

Publishers(others) = M / N x (N - 1) = M - M / N性能

那么每一个进程须要处理的推送路数为:测试

Publishers(all) = Publishers(self) + Publishers(others) = M / N + M - M / N = M

即每一个进程须要处理的推流数跟CPU个/核数是没有关系的,并不能用增长CPU个/核数来试图提升推流并发性能,即至关于本来能将M个推流请求“平均”分配到N个进程上的方案不但没起做用,还让每一个进程都处理了所有M个推流请求。

那么怎么解决这个问题呢?答案是使用被动拉的方案替代主动推(auto push)的方案。此方案要用到共享内存和互斥锁,当一个推流请求被某个进程接受后,在共享内存中记录推送的流和某个进程的映射信息。而当一个播放请求被某个进程接受后,须要先查找要播放的流是在哪一个进程上发布的,而后再到发布流的进程上去请求数据:

这样就解决了上述的每一个进程都要处理所有进程接收到的推流请求的问题。

关于nginx-rtmp-module的缺陷暂时介绍到这儿,其实nginx-rtmp-module还有不少其余的缺陷,后续有时间我会写文章介绍。

欢迎关注我在nginx-rtmp-module的基础上开发的项目:nginx-http-flv-module。

相关文章
相关标签/搜索