标签归档:nginx-rtmp

全民大直播,流媒体选择Nginx是福还是祸?

CDN,视频云,已经“僧多粥少”

视频直播的持续升温,无意间也让带宽生意的争夺变得异常残酷。一时间,各种云计算、CDN、视频云提供商都在视频尤其是直播上投入重兵,揭竿而起的新生起义军们也正马不停蹄的赶往这方战场,各种号称可以在IaaS、PaaS、SaaS不同层面提供平台级、接口级以及产品级服务的花式作战口号此起彼伏,让人眼花缭乱,“僧多粥少”可能成为了当前支撑视频技术解决方案市场最恰当的提法。如此局面之下,视频云和CDN们,技术上到底是在竞争什么?作为视频平台和即将要进入视频领域的运营者,在技术平台的选型和搭建上又如何才能避免掉入大坑?

一个播放器的背后

谁都知道视频直播最重要的是流畅和高清,但这光鲜亮丽的背后是技术和成本的双高门槛,是诸多技术环节艰难积累和苦逼的人肉运维。主播发起一个简单的直播,主干流程就历经了采集、编码、推流、转码、分发、拉流、解码和播放这么多环节,还要求在数秒内完成,除此之外直播还有如录制、流控、安全、审核等等诸多复杂功能需求。

再如下图,仅一个屌丝观众从播放器看这个主播,就可能出现如此多不可知情形发生。这个屌丝的接入网络怎么样?使用的系统环境又怎么样?一个观众尚且如此,要保障百万千万级别流畅的观看,难度可想而知。

高清流畅到底靠的是什么

也许对于部分视频运营商和新进入者来说,直播推流端和播放器端依然觉得头大,但整体来说,除移动端外,PC端推流和播放技术已经比较成熟。难,主要难在传输和分发!正常情况下,只要推流端网络状况良好,传输和分发决定着直播是否能够流畅。

传输和分发,涉及到了视频最核心技术、巨额服务器和带宽成本以及国内网络环境极度错综复杂也因为如此,视频平台基本上都将传输和分发环节交由专业的第三方视频云服务商或CDN服务商来完成。我们从网络传输的七层中拿出与视频传输分发相关的四层,如下图:

L2资源层:对视频云和CDN来说,资源的确存在差别,但在其可承受范围内,可以视为差别不大;

L4传输层:传输层可针对不同业务场景,比如针对超低延迟可以基于UDP做私有协议等。本文侧重阐述视频流畅的保障,不同应用场景的支持后续文章将专门介绍;

L3网络层:视频云和CDN公司在该层实现各运营商网间打通、多层Cache系统设计以及用户就近调度。该层的设计及优化对访问质量极为重要,随着CDN技术的日益成熟,虽然各家可能存在架构区别,但基本都能保障网络路由正常运转;

L7应用层:抛开细枝末节,视频流的主线还是输入、传输与输出,承担这些工作的就是视频平台最核心组件流媒体服务器,这就是视频直播分发最本质的特点,需要专门的流媒体服务器来分发,所有视频云和CDN,都需要在中心层和边缘层部署流媒体Server。

 

通过以上逐层分析可知,当资源和网络层面相差不大的情况下,流媒体Server的性能决定了视频流分发的效果和质量,故流媒体Server才是视频云和CDN技术竞争的至高点。



市面主要的流媒体服务器对比

目前市面上主流的流媒体服务器,有以Adobe FMS、Real Helix、Wowza为代表的第一代产品,它们的特点是单进程多线程。基于Linux2.7 epoll技术,出现了以多进程单线程为特点的第二代流媒体服务器,NginxRTMP、Crtmpd为其优秀的代表,另外还有基于JAVA的流媒体祖先Red5等。

观止云开源流媒体服务器SRS(Simple RTMP Server),凭借其功能强大、轻量易用、特别适合互动直播等诸多特点备受海内外视频从业者的青睐。蓝汛Chiancache曾用SRS承载其直播边缘分发业务,高升CDN基于SRS搭建其流媒体基础平台,其它还有赛维安讯、VeryCDN、VeryCloud、云博视等也将SRS应用到了自身的业务当中。各家视频云、云计算平台在源站的对接上也非常注重对SRS的支持。SRS作为纯国产的开源Server,在中国流媒体业界实属难能可贵。

观止云源站集群BMS(Bravo Media Server)是SRS的商业版,BMS在SRS基础上增强了11项大功能,新增了9个大功能

增项的11项大功能:



新增的9项大功能:





流媒体Server的话说来也不短,上述列举的目前市面上主流流媒体服务器中,有名副其实的先烈RED5,有生不逢时的CRTMPD,都未大规模商用就不过于讨论了。其中应用最为广泛莫属nginx-rtmp,以下是nginx-rtmp几个盛行于世的重要因素:

  • 2012年CDN业务开始极增长,随之直播需求也多了起来,彼时业界都还没有一套公认的特别满意的流媒体服务器;

  • Nginx是HTTP领域绝对的霸主,大家(尤其是CDN运维)对Nginx熟悉程度很高,便于上手维护;

  • 基于Nginx,直播点播使用一套服务器,这也极具诱惑力,一套管理起来总比多套要简单;

  • CDN是靠运维的行当,运维的信心都是长年运出来的,Nginx在图文上那么优秀,Nginx RTMP也差不了。



nginx-rtmp确实生来就自带光环外,性能也的确是高,比Crtmpd还要高。然而,时过境迁,随着互动直播、移动直播的强势兴起的大直播时代,选择nginx-rtmp到底是福还是祸?

下面小编将从协议支持、体系架构、核心功能支持、配置运维、性能、服务器日志、数据这七大维度将目前市面主流的流媒体Server做一个横向对比,供视频从业者根据自身业务场景特性择优选用。



1
网络协议对比

BMS支持HDS、DASH、RTMPE/S/T等协议的分发,这将支持更多业务应用场景,FLASH P2P的支持能够显著降低网络带宽成本。



2
体系架构对比

架构方面,较之于nginx-rtmp的16万行代码,SRS仅用了6.5万行代码就实现了比nginx-rtmp 多了230%的功能nginx-rtmp注释率为3%,而SRS是23.7%。由此可见SRS在体系架构上的轻,Simple。

观止云BMS在SRS的基础上新增了多进程支持、源站集群、动态配置、可追溯日志等方面能力。源站集群子系统打通了跨网跨地区的源站分布式部署难题;动态配置子系统从业务系统读取配置,依据更新机制动态更新配置,保证直播业务配置变化时依然不中断;端到端的可追溯日志及监控排错子系统将直播故障定位时间缩短到了分钟级别。



3
核心功能对比

核心功能方面,BMS支持了当期互动直播、移动直播急需的大规模直播流实时转码、大规模录制、秒级低延迟、HLS+、并发回源等其它所有流媒体系统不具备的功能。HLS+基于每个播放请求实现了流媒体的“虚拟连接 ”(UUID标识),在减小回源量、排错、防盗链、移动Web端低延迟等方面具有诸多优势。并发回源能够解决回源网络状况差、跨国传输丢包严重等方面能够显著提升回源质量。



4
配置运维对比

以下仅是流媒体众多配置之中几个常用例子,运维日常工作中,需要操作的配置数量更多。

(1)vhost配置

FMS

拷贝默认vhost目录:sudo cp -r conf/_defaultRoot_/_defaultVHost_ conf/_defaultRoot_/bravo.sina.com



nginx-rtmp

不支持



SRS/BMS

动态获取配置文件:vhost bravo.sina.com { }

结论:BMS动态获取配置最简单

(2)app配置

 FMS

拷贝默认app目录:cp applications/live applications/mylive -r



nginx-rtmp

修改配置文件,增加如下内容:application live {  live on; }



SRS/BMS

无需配置

结论:BMS无需配置,最简单 

(3)http配置

在输出为hls、http-flv等基于http协议的直播流时,需要配置http服务

FMS

配置FMS内置的Apache服务器文件:Apache2.2/conf/httpd.conf

再修改如下字段:

<Location /hds-live>

    HttpStreamingEnabled true

    HttpStreamingLiveEventPath “../applications” 

    HttpStreamingContentPath “../applications” 

    HttpStreamingF4MMaxAge 2

    HttpStreamingBootstrapMaxAge 2

    HttpStreamingFragMaxAge -1

    Options -Indexes FollowSymLinks

</Location



nginx-rtmp

nginx本身就是一个http服务器,

修改其配置文件:

conf/nginx.conf

设置端口和根目录:

http {

    include       mime.types;

    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {

        listen       80;

        server_name  localhost;

        location /dash {

            root /tmp;

            add_header Cache-Control no-cache;

        }

    }

}



SRS/BMS

修改其配置文件:

conf/http.hls.conf

设置端口和根目录:

http_stream {

    enabled         on;

    listen          8080;

    dir             ./objs/nginx/html;

}

结论:nginx-rtmp需指定与app对应的ts文件存放目录,SRS/BMS会自动生成,更简单。

(4)推流、播放URL配置

RTMP直播时,各大服务器推流、播流URL均为:

rtmp://server_ip_or_dns/app/stream



用作HLS直播时,

FMS 

推流域名:

rtmp://fms-ip-or-dns/app/stream?adbe-live-event=liveevent

播流域名:

http://fms-ip-or-dns/hds-live/app/_definst_/liveevent/stream.f4m



nginx-rtmp

推流域名:

rtmp://server_ip_or_dns/app/stream

播流域名:

http://server_ip_or_dns/app/stream.m3u8



SRS/BMS

同nginx-rtmp

结论:nginx-rtmp、SRS/BMS均简单,FMS较复杂。



5
性能

先说结论:

SRS单进程能支持9000并发,nginx-rtmp单进程最多支持3000个,单进程的性能SRS是nginx-rtmp的三倍。单进程性能SRS > nginx-rtmp > crtmpd > wowza > fms > RED5

 

再例举SRS性能如此高的几个原因:

1. st-load,这个是SRS能做到高性能的最重要的原因,一个st-load可以模拟2000+的客户端,如果没有st-load,如何知道系统的性能瓶颈在哪里?总不能打开3000个flash页面播放rtmp流吧?开启3000个ffmpeg来抓流?高性能不是想象和猜测出来的,而是反复测试、调试和改进出来的。

2. gperf/gprof性能,编译SRS时,就可以打开gcp或者gprof的性能分析选项,非常方便的拿到数据。缩短了改进和优化开发周期。

3. 引用计数的msgs避免内存拷贝。

4. 使用writev发送chunked包,避免消息到chunked包的内存拷贝。

5. mw(merged-write)技术,即一次发送多个消息。

6. 减少timeout recv,每个连接都是一个st-thread在服务。

7. fast buffer和cache。

8. vector还是list?vector!vector比list高10%性能。



6
服务器日志

日志是定位故障的唯一途径,定位故障才能快速排错。可以这么说,对于直播,10分钟的排错,谁都会觉得长。然而,当前的视频云或CDN,谁又能做到10分钟呢?

来看看日志吧。

FMS的日志是这样的,恕我愚钝,你能看得出什么信息么?

2015-03-24 12:23:58 3409 (s)2641173 Accepted a connection from IP:192.168.1.141, referrer:http://www.ossrs.net/players/srs_player/release/srs_player.swf?_version=1.23,pageurl: http://www.ossrs.net/players/srs_player.html?vhost=dev&stream=livestream&server=dev&port=1935-

702111234525315439     3130         3448         normal      livestream         –        –         rtmp://192.168.1.185:1935/live/livestream     rtmp://192.168.1.185:1935/live/livestream        –        flv     –        –        0       –        0       0         –        –    http://www.ossrs.net/players/srs_player.html?vhost=dev&stream=livestream&server=dev&port=1935    -1      -1.000000         

crtmpd的日志详细,但我又愚钝,若是上千人在线,你又能看出什么有用的东西么?

/home/winlin/tools/crtmpserver.20130514.794/sources/thelib/src/netio/epoll/iohandlermanager.cpp:120Handlers count changed: 15->16 IOHT_TCP_CARRIER

/home/winlin/tools/crtmpserver.20130514.794/sources/thelib/src/netio/epoll/tcpacceptor.cpp:185Client connected: 192.168.1.141:54823 -> 192.168.1.173:1935

/home/winlin/tools/crtmpserver.20130514.794/sources/applications/appselector/src/rtmpap

用nginx-rtmp的63%代码,增加80%的功能,SRS用到的ST是个什么球?

这次我要讲的是:ST(state-threads)是个什么球?

趁着吃完饭休息会儿,给大家讲讲ST(state-threads),一个四两拨千斤的想法。基于ST的SRS1只用了4.3万行(63%)代码,比nginx-rtmp多了83%的功能,周期缩短100%;而SRS2只用了6.5万行(95%)代码,比nginx-rtmp多了230%功能。开发周期SRS1用了1年,SRS2用了1年;nginx-rtmp发布1.0用了2年。啥都不说了,SRS3就不再和nginx-rtmp比了,SRS3和SRS2比吧~

如果说代码行数不能说明问题,那再爆料一组数据,SRS1的注释率是22.1%,而SRS2的注释率是23.7,nginx-rtmp注释率是3%。可见SRS用ST简化了多少逻辑。nginx-rtmp的6.8万行代码,是去掉了其他模块,只有core和rtmp等必要模块,总共nginx-rtmp有16万行代码。

ST解决的是服务器的最根本问题:如何以最高效率服务多个客户端连接?答案就是nginx的架构,即单线程异步非阻塞socket(没错还有多进程,我们先只考虑如何一个进程最高效);在linux中,就是epoll+send(MSG_DONTWAIT),具体的可以翻翻书柜,epoll早就不是什么新鲜事了。

这个架构可以打个比方,一个快递员在送快递时,假设有4个客户分别在四个完全不同的方向,东家西家南家北家,快递员每家都要送1000个包裹,快递员的货车有限先送东家1000个包裹,东家收了100个候发现家里没有空间了得腾缓冲区出来,快递员只好暂时不管东家了(非阻塞啦),去给西家送了200个还有800个,南家300个还有700个,北家1个还有999个。

接下来肿么办?最快的方式当然是各家的空间腾出来后,快递员用epoll_wait就知道哪些可以继续了,这就是异步啦。这个异步非阻塞是相当高的效率,但是麻烦的地方在于,快递员每次都要登记各家的状态,然后跑到各家去继续送(调用不同的处理函数),路上不仅浪费很多时间,而且维护这些信息非常之麻烦啊!每次都得把路重新计算规划,再跑一边非常需要费脑筋啦。

最简单的方式是不要登记各家状态,每家都派一个快递员啦(创建线程),各家有空间这个快递员马上就继续发,这样是最简单的逻辑;缺点是要做线程同步咯,而且很昂贵啦,没法一下子服务几万个用户。

孙悟空的毫毛可以用在这里,分身术,实际上还是一个快递员,但是在各家那里分个身。好处是不用登记那些信息,各家有空间了立马就开始写;比线程的优势是不用锁,开销小。ST就是分身术,虚拟线程,即用户空间线程协程,类似goroutine,或者C#的纤程。

协程完全是不同于进程和线程的一套写代码思路,解决问题的思路不一样,当然结果是不一样的啦。在处理rtmp的edge,以及http-flv的hstrs(http stream trigger rtmp source)时,涉及到多个线程交互,这种就相当于两个异步状态空间相乘,那个是相当之复杂的。这是为何nginx-rtmp实现RTMP比较费劲,要实现RTMP-EDGE,以及HTTP-FLV、HSTRS是非常难的事情。

关于ST更多信息,请参考:http://blog.csdn.net/win_lin/article/details/8242653

比nginx-rtmp高三倍性能的SRS的高性能是个什么球?

SRS单进程能支持9000并发,nginx-rtmp单进程最多支持3000个,单进程的性能SRS是nginx-rtmp的三倍。SRS单进程性能如何做到nginx-rtmp的三倍的?SRS哪几个结构极大提升了性能?

先来看看我们遇到的问题,RTMP协议和HTTP协议是又很大不同的。nginx在分发HLS,即m3u8文本文件和ts视频文件时,对所有连接发送的都是同一个内容,甚至可以调用sendfile让内核自己发fd去,nginx服务器自己要干的事情很少了;如果nginx必须把每个ts的内容读出来,修改里面某些字节,然后每个客户端一次发送的数据前还得加点什么,nginx就会很忙了。

这就是RTMP,每个video或audio包,在发送给某个连接之前,都得修改下时间戳(至少FMS是每个连接收到的媒体数据都是从0开始的时间戳),然后把包再拆分成一些小片段(chunked),每个chunk包前面加几个字节的头信息,然后发送。我勒个去~

举个例子,假设有个视频的I帧有200000bytes,默认的chunk包最大是128字节,所以得拆分成200000/128=1562个chunk包来发送,每个chunk包前面都要加chunk头。没有办法sendfile了吧?可以想象得到内存要被蹂躏成什么样子吧?这就是RTMP流媒体服务器麻烦的地方了,客官可以自己想下搞个什么样子的算法能最高效发送粗去~

nginx-rtmp是性能最高的服务器,比crtmpd都要高,red5根本就低两个级别,wowza也没有它高。SRS做了什么能够比nginx-rtmp单进程还要高三倍?

第一点,st-load,这个是SRS能做到高性能的最重要的原因,一个st-load可以模拟2000+的客户端。一个牛逼的benchmark的工具;如果没有st-load,如何知道系统的性能瓶颈在哪里?总不能打开3000个flash页面播放rtmp流吧?开启3000个ffmpeg来抓流?不靠谱。这就是高性能第一定律:高性能不是想象和猜测粗来的,而是测试、调试和改进粗来的。

第二点,gperf/gprof性能benchmark功能。在编译SRS时,就可以打开gcp或者gprof的性能分析选项,灰常方便就可以拿到数据。缩短了改进和优化的开发周期。

第三点,引用计数的msgs避免内存拷贝。从编码器收到的video/audio数据,转换成SrsSharedPtrMessage放到每个连接的发送队列,避免每个都拷贝一次;因为发送给每个客户端的消息(不是chunked包)头可能不一样,譬如时间戳不一样,但是消息的payload是一样的。

第四点,使用writev发送chunked包,避免消息到chunked包的内存拷贝。可以开辟一个header的缓冲区,专门放每个chunked包的header,然后用iovc保存头的指针和大小,payload的指针和大小,用writev就可以一次发送。

第五点,mw(merged-write)技术,即一次发送多个消息。虽然每个消息使用writev可以避免拷贝,还有更高效的是一次发送多个消息,即把多个消息的chunked头写在header的缓冲区,iovc保存多个消息的chunked头和payload指针,一次writev发送多个消息。这个是最关键所在。

第六点,减少timeout recv,每个连接都是一个st-thread在服务。在发送之前,线程得尝试从连接收取消息,譬如客户端的stop之类的;所以只能recv时指定timeout,譬如300毫秒如果还没有收到消息,就发送连接队列中的消息。这个会导致st的timeout红黑树操作频繁。实际上,可以直接开启一个recv线程,因为客户端的消息非常少,避免timeout接收。

第七点,fast buffer和cache。譬如每次取消息的数组,使用cache;使用fast buffer避免频繁删除;使用header的cache。

第八点,vector还是list?有的地方看起来list更高效,譬如simple buffer这种频繁删除头,以及在结尾加入数据,看起来是list应该做的事情。但是实际上测试发现,vector比list高10%性能。所以,回到第一点,高性能不是猜测和想象粗来的;有的时候有些代码写得很慢,但是这个频率非常低,那么就不要考虑性能,而要考虑可读性。我觉得可以算是高性能第二定律:不要总是考虑高性能,可读性更重要。

另外,nginx-rtmp有多进程啦。没错,可惜SRS也可以有多进程啦;可以有为何没有做呢?首先,9000个连接还不够么?1Mbps的码率可以到9Gbps了哦,伦家的机房交换机有那么牛逼么?敢一个服务器服务那么多用户么?其次,多进程不是万金油的,不过是一种技术,不是没有多进程就低人一等,有了多进程就高人一等,别那么技术控,关键在于对于客户有啥价值。再次,可以用RTMP302支持多进程,这个是最稳定的多进程技术。最后,杰哥的BLS已经实现了多进程,他设计的多进程架构,即一个源站fork多个边缘的进程的结构,是最简单的多进程通信模型。这可以引申出高性能第三定律:表当真呢,高性能不是万金油。

SRS的性能测试,请参考:https://github.com/winlinvip/simple-rtmp-server/wiki/v1_CN_Performance

SRS的性能优化commit,请参考:https://github.com/winlinvip/simple-rtmp-server/tree/2.0release#performance