一、概述
流媒体服务器(视频服务器)是在线视频应用的核心系统,用于支持海量大并发的视频播出服务,实现将视频存储、视频转码、协议复用、大并发播出等的工作集中处理,业务系统可以只关注业务细节而不用再去处理与视频相关的诸多技术细节,从而实现提高项目实施效率、降低项目实施风险的目标。
那么流媒体服务器是如何实现高负载大并发的呢,其中有几项技术细节至关重要,下面以流媒体服务器 NTV Media Server G3 所采用的技术细节为例来说明。
二、关键技术
1、epoll技术
epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。
epoll的主要优势包括:
1)支持一个进程打开大数目的socket描述符
select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是1024。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译服务器代码,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max查看,一般来说这个数目和系统内存关系很大。
2)IO效率不随FD数目增加而线性下降
传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时,任一时间只有部分的socket是“活跃”的,但是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对“活跃”的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有“活跃”的socket才会主动的去调用 callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个“伪”AIO,因为这时候推动力在os内核。在一些 benchmark中,如果所有的socket基本上都是活跃的---比如一个高速LAN环境,epoll并不比select/poll有什么效率,相反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。
3)没有使用mmap加速内核与用户空间的消息传递
2、sendfile技术
Linux系统的sendfile 函数实现在两个文件句柄之间直接传递数据,避免了内核缓冲区和用户缓冲区之间数据的拷贝,操作效率非常高,称为零拷贝。传统的编程,从文件到网卡发送文件数据,需要在两个缓冲区之间拷贝数据,使用sendfile函数,可以直接通过共享文件指针来实现。linux系统开发指南是这样描述的:
“sendfile() copies data between one file descriptor and another.Because this copying is done within the kernel, sendfile() is more efficient than the combination of read(2) and write(2), which would require transferring data to and from user space.”
原型定义如下:
#include<sys/sendfile.h>
ssize_t sendfile(int out_fd,int in_fd,off_t*offset,size_t count);
3、文件指针复用
对于视频点播应用,理想的情况是在大并发情况下很多用户在访问有限的数个热点资源,这时候优化的空间就很大。如果为每个用户请求单独打开一个文件句柄,那么就无法在进行文件指针复用,磁盘IO和内存会显著增高。如果我们只为每个相同文件打开一个句柄,多个用户请求一个文件时进行读指针复用,情况就会好的多。另外,这个打开的文件会被加载到内存里,众多的读操作只是在内存中进行,而不是进行磁盘读写,这个操作对消除磁盘IO瓶颈起到了关键作用。
三、超大并发的处理
当并发量超过1万,达到数万甚至数十万时,在单机上进行优化的手段就显得力不从心了,这时候需要从网络架构和集群的较多去考虑问题。NTV Media Server G3有两种方案处理海量并发,一是集群方案,通过多台服务器之间建立负载均衡来实现大并发;二是CDN加速方案,通过与CDN系统建立加速配置关系,将负载转移给CDN,实现全球范围的大并发播出。 当然,CDN与流媒体服务器的负载已经没有太多关系,是另外一个可以独立探讨的技术话题。