用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