流媒体服务器的性能可以从抗抖动能力、拥塞率和卡顿率等方面进行分析。当用户访问的频率过高或者并发的数量超过流媒体服务器所能承受的范围时,必须考虑通过限流来保证接口的可用性,从而防止出现因请求数量过多、压力过大造成服务器瘫痪等现象。因此,怎样提高流媒体服务器的抗抖动能力,平滑发送流量,降低卡顿率,减少丢包率是本文描述的重点。
前面的CDN的文章对一些相关算法进行了比较分析,对CDN流媒体的关键技术也进行了选取。本文就基于Nginx 服务器,结合 HLS 流媒体协议与令牌桶算法,针对流媒体服务器的数据处理模块、缓存模块与发送模块进行设计。
流媒体服务器的数据处理逻辑可分为以下几个部分:
(1) 数据处理模块:
数据处理模块主要负责以下几个功能:
(a) 接收来自客户端的请求和来自上级服务器的发送数据。
(b) 负责数据代理转发,在本地没有直播缓存数据时,需要向上级 CDN 或者源站发送请求从而获取数据,再把数据转发给客户端。
(c) 将录制频道的直播流文件写入存储系统,支持回看功能。
(2) 缓存模块(Cache 模块):Cache模块用来从磁盘或者内存中读取实体文件,解析出文件码率,分包后对数据包进行时戳标记,并将标记好时戳的数据包压入数据发送模块。
(3) 发送模块(Shaper 模块):Shaper 模块的主要功能是将 Cache 模块输入的数据发送至客户端。Shaper 模块在进行数据处理时会根据当前的发送状态控制发送速率。Shaper 模块中的队列提供 FIFO(先进先出)的数据重传功能,保证数据在重传时不会乱序。流媒体服务器框架设计结构图如下所示:
数据处理模块在收到来自客户端的请求后,会根据请求内容从 Cache 模块中寻找相应资源,如果 Cache 模块有相应的资源,则直接将数据交由 Shaper 模块进行发送处理;如果 Cache 模块中没有相应资源,则会主动到本地磁盘进行资源查找;如果本地磁盘也没有相应资源,则会通过数据处理模块向源站发送请求信息,数据处理模块接收源站的相应数据并将数据存放在存储服务器中,最终 Shaper 模块负责将用户所请求的内容返回给客户端。有时,对于一些热门的视频业务,数据处理模块会提前向源站请求资源存入存储服务器中,当用户请求到来时可以及时作出响应。
2.流媒体服务器数据处理模块设计
2.1 数据接收和转发模块设计与实现
在处理多客户端请求时,可以在服务器端创建多个进程,但这种做法显然有一些弊端,创建进程本身是一个消耗计算机资源的过程,一味地创建进程也无法应对快速发展的业务量。I/O 多路复用技术让一个进程可以处理多个客户端需求,使得上述问题得以解决。这里也会涉及到很多优化,所以我们需要考虑到可以使用更优秀的商用框架。
I/O 多路复用技术可以理解为通过一种机制来监视多个文件描述符(文件描述符是计算机术语,用来表示指向文件的引用),当某个描述符就绪,对程序进行相应通知来完成读写操作。在 I/O 多路复用的解决方案中,有 select、poll 和 epoll 三种方式,这三种方式的本质都是同步 I/O。当然也可以做到异步。
epoll 模型不仅会告知应用程序有 I/O 时间到来,还会告知 I/O 流的相关信息,因此,应用程序不必遍历整个文件描述符集合就能定位到 I/O 事件,其时间复杂度为 O(1)。在性能上,select 模型和 poll 模型都会随着连接数的增加性能急剧下降,而 epoll 模型在处理成千上万的并发时,性能没有很大的改变,且其对连接数上限没有限制。epoll 模型最大的优点在于它只关心活跃的连接,而不关心总连接数,因此在实际的网络环境中,epoll 的效率远超于 select 模型与 poll 模型。epoll 除了在开发复杂度上略有难度,在内部使用数据结构、内核空间以及内在处理文件描述符机制等方面都优于 select,最重要的是,epoll 是实现了高并发的基础。select、poll 与 epoll比较如下图所示:
Nginx 已有的数据处理模块就是基于 epoll 技术实现的,采用回调机制(callback)实现所有接收数据相关的函数,数据处理模块结构图如下所示:
代理转发模式下,nginx_http_upstream_init_request 函数作为该模式的入口函数,将此函数注册到 nginx_http_upstream_process 中,当进入调用链时,将需要监控的 epoll 句柄加入到nginx_add_event 中,在和上级源站建立连接成功后或者有数据交互时,epoll 监控到的句柄被触发,从建立连接,发送请求,接收数据(此过程称为代理回源)。
在数据接收流程中,ngx_event_accept函数作为该模式的入口函数,在系统启动时,通过注册到 nginx_event_process_init 函数中,将需要监控的 epoll 句柄加入到 nginx_add_event中。当有客户端请求时,epoll 监控的句柄被触发,进而对连接请求进行处理。
2.2 数据录制模块设计与实现
Nginx 目前没有提供支持 HLS 或者 TS 协议的录制模块,本文采用 epoll 异步通知机制,设计录制模块,数据录制模块异步线程调用关系图如下所示:
上图中,Proxy 线程与文件 I/O 线程都是 Nginx 自带的模块。Proxy 线程负责接收来自于源站的请求数据,它将每个请求的文件描述符 fd 句柄加载到 epoll 中,再分发到各个录制线程中,同时通过调用 submit_task()接口把录制任务传递到录制线程中。录制线程则是把接收到的录制任务数据进行整合(包含对录制任务数据进行拼装、去重、校验、容错等步骤)后,同样将对应的文件描述符 fd 句柄加载到 epoll 中为 I/O 线程进行调用,同时调用 submit_task()接口进行异步写盘。在进行异步写盘时,默认写盘数据大小一般设置 1MB 作为基本单位,这是因为当写盘数据大小高于或是低于 1MB 时,内部存储器调用 read()函数次数过多,会导致 CPU过高,且数据排列组合多,浪费时间。因此选择 1MB 作为基本单位进行数据写盘时效率最高。文件 I/O 线程负责接收录制线程发送来的数据,是 Nginx 已封装好的模块,可以直接调用。
2.3 流媒体服务器数据缓存模块设计
在传统的 Nginx 流媒体服务器中,只有直播业务会采用缓存机制(Cache),但对于点播业务来讲,传统的 Nginx 流媒体服务器没有 Cache 机制。点播业务会采用直接读取磁盘上数据文件的方式,这种方式会导致磁盘 I/O 读写频繁,不仅影响系统效率,还会加速磁盘老化。因此,本节基于 Nginx 流媒体服务器,在点播业务上新增缓存模块,流媒体服务器会先从 Cache模块中获取所需要的数据,如果 Cache 模块中没有找到,才会从本地磁盘进行读取,这大大减少了磁盘的读写,从而减少系统开销,使性能得以优化与提升。
(1)Cache 模块模型架构
Cache 模块包含了 Cache 模块与本地磁盘的交互方式。当客户端发起请求后,数据接收模块会根据请求内容在 Cache 模块中寻找对应文件内容。Cache模块中的 Cache_read()函数和 Cache_open()函数分别负责对内容资源的读取与打开。请求来临时,服务器会根据用户请求所对应的文件描述符 fd 调用 Cache_read()函数进行内容读取,之后调用 Cache_open()函数打开文件。若此时从 Cache 模块中获取到了相应资源,则直接将资源交由 Shaper 模块进行发送处理;若没有从 Cache 模块中获取到相应资源,则会根据文件描述符 fd 从本地磁盘中进行查找。
(2)本地磁盘包含两大模块,分别为 IO_open 模块和 IO_read 模块,其功能与 Cache 模块中的 Cache_read()函数和 Cache_open()函数类似,负责对内容资源的读取与打开,但调用方向有所区别。
当在 Cache 模块中没有获取到索要找寻的数据时,会先调用本地磁盘的 IO_open 模块将文件打开,并将文件描述符 fd 返回给 Cache 模块中的 Cache_open()函数,之后调用 IO_read模块进行文件内容读取,并将读取的内容返回给 Cache 模块中的 Cache_read()函数。这样一来,Cache 模块中的数据会得到及时更新,当请求相同的资源时会直接从 Cache 模块中进行读取,从而减少了对本地磁盘的操作。对于长时间没有被请求的内容 Cache 模块会对其定期清理。Cache 模块模型架构图如下所示:
Cache 模块从功能层面来讲可以分为两大部分:
(3) Cache_block:用于存储文件数据块的内容和相关信息。
(4) Cache_file:是应用层进行文件操作的基本单元,使用文件句柄 Cache_fd 作为基本凭证。Cache_file 包括两种 block,分别为 cache_block_list 和 uncached_block_list,如下图所示:
2.4 Cache 模块的主要接口设计
Cache 模块的主要接口设计如下:
(5) Cache_open()
文件打开接口,主要功能如下:
(a) 查看文件状态。
(b) 在文件 hash 表中查找文件是否已经被打开,如果已经被打开,则刷新引用计数(ref),并直接返回;如果未被打开,则在 hash 表里增加一个表项,并使用 dump_file()接口打开该文件。
(6) Cache_read()
读文件接口,主要功能如下:
(a) 增加文件引用数。
(b) 在 cache_file 的 block_list 中查找块是否存在,如果存在则直接返回给调用者;如果未找到,则向空闲块列表中申请一个新的块。
(c) 调用 dump_file()接口进行文件读取。
(d) 将块加入到 used_list 和 cache_file 中。
(3) File_closed()
文件关闭接口,主要功能如下:
(a) 减少引用计数,一旦引用计数为 0,则执行文件关闭流程。
(b) 同步调用 dump_file()接口来关闭文件。
(c) 同步和异步销毁 cache_file 文件,其中需要清空 cache_file 文件所拥有的 block_list。
(4) Io_read() 文件预读接口,主要功能如下:
(a) 检查 block 是否已经在 cache 中存在,如果存在则无需进行预读。
(b) 向预读线程提交预读任务,预读从线程中增加文件的引用计数,防止预读过程中,文件被关闭。
(c) 调用 cache_read()接口,同时回滚文件的引用计数。
(5) Block_aging()
块老化接口,主要功能如下:
(a) 遍历 used_list,将引用数为 0 的 block 块加入老化列表,并按照时间排序。
(b) 遍历老化列表,将排名靠前的 N 个块从 used_list 中摘除,放入 free_list,一旦空闲块数量达到要求(阈值的两倍),则停止老化。
2.5 Cache 模块的功能设计与实现
Cache_file 用来存储一个个的缓存数据块,数据块包括两种,cache_block_list 和 uncached_block_list。在对这两个模块进行数据存储时,可供选择的数据结构有链表、二叉树、哈希结构等
(1) 链表(含单向链表、双向链表)链表的特点是便于元素的增加与删除,开销较小,但在对元素的查找时效率很低。因此其多用在数据量较小,且不需要排序的场景。
(2) 二叉树(含红黑树、平衡二叉树)
二叉树的特点是在插入任意元素时都可以自动进行排序,使元素保持有一定的特性。由于二叉树的空间占用与输入的数据保持一致,所以不需要为二叉树预先分配固定的空间。因此,二叉树多是用在频繁对数据进行增删和查询操作的场景下,在增删改查的同时需要时刻保证数据的有序排列,且无需预先知道数据量的大小。二叉树的时间复杂度是 O(log(n))。
(3) 哈希(hash) 哈希结构使用链表和数组来管理元素,在理想的哈希算法的支持下可以达到接近数组的随机访问效率,因此其使用场景为无需保证元素的有序性且频繁对数据进行操作的场景。流媒体服务器应用在多用户直播或点播场景中,此场景的数据特点是数据量大且保存媒体文件时无需排序。当一个用户请求某一路直播(比如 CCTV2),哈希结构可以快速根据 CCTV2 的 hash 值很快找到对应的缓存块,从中读取数据,时间复杂度可以近似达到 O(1)。若使用链表或二叉树,需对缓存中的每项内容进行遍历,时间复杂度较高。其次,媒体文件本身并无排序需求,不符合二叉树的使用场景。另外,哈希结构的代码开发简便且可维护性较强。综上选择使用哈希数据结构对流媒体服务器的 Cache 模块进行设计开发。
在数据量较大时,哈希结构会产生冲突。解决哈希冲突采用的方案有两种:第一种是线性探索,相当于在冲突之后建立一个单链表,这种情况下,插入和查找以及删除操作消耗的时间会达到 O(n);第二种方法是开放寻址,这种方法不需要更多的空间,在最坏的情况下,时间复杂度也只会达到 O(n)。
Cache_file 的哈希结构在 Cache 模块中的实现方式。哈希表的 key 值是由点播或者直播的媒体文件名通过哈希表达式计算得来。每一个 file 文件后又以链表的形式存有若干block,当需要查找资源时,只需按照哈希表达式来进行查找即可,这样的数据查找方式在一定程度上提高了查找效率。Cache_file 的哈希实现方式如下所示:
(4) 在读取数据入队之前,Cache 模块会将数据打上时间戳,时间戳的计算方法模拟令牌桶原理,每一个数据包的时间戳计算公式如下:
T 为当前数据包的 RTC 时间戳,size 为当前数据包的大小,TS 格式下的媒体元数据单位是 1316 字节,speed 为当前流媒体文件码率,t 为上一个数据包的 RTC 时间戳。从公式可以看出,计算单位时间 1 秒内发送的报文数 n,可利用如下公式:
即给 n 个数据包打上时间戳。即在 time 秒内理论发送数据可以达到如下公式:
从上面的步骤可以看出,通过给数据包打 RTC 时戳的方式,可以计算单位时间内的发包个数,从而对其进行精确控制,实现均匀控制码率的效果,与传统令牌桶的实现方式相比,这种时间戳控制方式,在保证速率控制的同时,减少了发送模块对令牌结构出队入队(保证一定的数据包个数),申请内存等操作,提升了系统性能。
3.发送模块设计
Shaper 模块即数据发送模块,主要负责将 Cache 模块入队的数据进行发送,并计算发送结果,根据单位时间内发送的字节数 B 计算出当前的链路带宽 b,实时更新每一个发送对端的链路速度,针对每一路用户的数据流进行数据降速或者升速。上面和下面这些公式就说明怎样去控制发送速率,非常重要。
3.1Shaper 模块模型架构
流媒体服务器发送模块的结构如下图所示,图中说明了数据的流程。
(1)本系统结合具体的业务场景增加了桶水位线的优化:如果当前媒体文件的码率为 s,流媒体服务器数据缓存模块以每 1/s 的精度,从当前 RTC 时钟自加,给每个数据包作时戳标记。数据发送模块预先开辟大小为 m 的队列,将做好时间戳标记且需要发送出去的数据入队,当数据包到达发送时间后,获得令牌,出队发送,每个队列有一条上水位线 H 和下水位线 L,当网络阻塞时,若队列内的数据大于等于 H,则新到的数据不入队,队列中的每个数据时戳向后移动 d 个精度,这样降低了发送速率,减少了网络拥塞。降低后的速率为 如下计算公式:
当网络状况良好,无发送失败记录,并且队列中的数据量在[L,H]之间,则将令牌生成间隔相对提高%d,按缓慢升速发送,如下计算公式:
直到队列水位线下降到 L 处,为了保留缓存,数据发送速率恢复到媒体文件码率 s,当数据发送成功后,该数据的令牌被销毁。所以令牌桶的原理就是通过控制令牌产生的速度,将数据发送码率平稳在 s 左右,对于每一个连接,令牌桶的数据流量为 B,计算公式如下:
3.2 Shaper 模块运行机制
Shaper 模块设计采用异步多线程运行机制,应用添加线程包中的数据来自于本地磁盘或是 Cache 模块中的数据文件。Shaper 模块中创建若干个发包线程,这些线程采用异步方式可以对应用添加包中的数据同时进行操作,这样做的好处就是,当多个请求发来且访问同一资源时,无需等待资源访问结束,在空闲等待时同时可以访问其他资源,提高了服务器的发送效率。如下图所示:
3.3 令牌桶在 Shaper 模块中的应用
将具体叙述如何将令牌桶算法应用在 Shaper 模块中以及应用令牌桶算法对流量整形产生的影响。在服务器的内部存储池中设计令牌产生模块,实现以一定速率产生令牌。这些令牌在代码中的具体实现是一些虚拟的数据包,当流媒体服务器接收数据时,会根据系统设定的匹配规则对接收的数据进行分类,符合规则的数据交由令牌桶处理,而不符合规则的数据包,直接拒之门外。Shaper 模块的数据来源有两处,一处是来自 Cache 模块,一处是来自本地磁盘。不论数据来自哪里,Shaper 模块都会将收到的数据打包并作时戳标记之后放入队列。数据包根据时戳会决定何时出队发送,出队后的数据包会在内部存储池中求取令牌,只有拿到令牌的数据包才可发送给客户端。当数据包没有获得令牌(通常是令牌桶中的令牌不足的原因造成),服务器为队列设置阻塞模式,数据包无法出队,阻塞在队列中。若阻塞数据包超过了队列的上线,则新的数据包无法入队。因此,我们可以通过控制令牌的产生速率来控制数据包的出队入队速率,从而达到对流量的控制。令牌桶在 Shaper 模块中的应用如下图所示:
假设令牌桶的容量为 D(单位:字节),产生令牌的速率为 v(单位:字节/秒),输出数据的最大速率为 V(单位:字节/秒),突发的时间为 s(单位:秒)。当突发数据来临前假设桶中的容量为 D-C,则有:
经过变型,则有:
由此可以计算出所能承受的突发时间,从而可以根据系统突发时间上限在代码中进行设置。
令牌桶实现 Shaper 模块的主要接口如下:
(1) bool Udp Shaper Channel()
此函数实现的功能是以 UDP 方式发送媒体数据,首先根据时间戳下发 ret 数据,之后发送媒体数据,如果成功则返回 True,失败则返回 False。
(2) void Interleaved Shaper Channel()
此函数首先发送信令(发送信令的时戳为当前时间),再根据时戳决定当前是否要发送媒体数据。若到达发送媒体数据的时间则进行发送;若没有到达,则等待。由于 TCP 有拥塞控制,当发送失败时,数据包的时戳时间会改为当前时间加上延迟时间。
(3) void Download Shaper Channel()
此函数功能为下载媒体数据,负责发送码率的升速与降速。在函数中设置发送码率的上线发送码率,同级周期内(1s)若发送失败率为 0,则提速 5%;若发送失败率小于 10%,则降速 5%。设置升速时,升速不能超过发送码率的上线,降速不能低于 12Kbps。
3.4 数据重传
Shaper 模块在发送数据包的过程中极有可能发生包丢失等异常情况,本系统在 Shaper 模块中增加重传逻辑用以应对此类情况。设计逻辑图如下图所示:
Shaper 模块在进行数据传输时,会根据 send()函数返回值对数据是否有丢包进行判断。例如,在传输 10 个数据包的情况下,当 send()返回值为 7 * 1316 字节(1316字节为 TS 格式下的媒体元数据单位),即说明有 3 个数据包在传输时发生丢失,此时根据时戳将待传输的数据包加入重传队列,在下次传输数据时优先传输重传队列中的数据包,之后再对 Cache 模块中的新数据队列进行传输。具体重传时间的计算公式如下:
4 流媒体服务器参数优化
Nginx 服务器的配置系统很灵活。只需通过对配置项的增加、修改即可实现第三方模块的信息提供。将对 Nginx 服务器与内核的配置文件进行相关设置,从而实现流媒体服务器的参数优化。
4.1 流媒体服务器配置文件优化
为了提高 Nginx 服务器的性能,需对流媒体服务器进行参数调优。Nginx 可以通过修改默认安装路径下/usr/local/nginx/conf/nginx.conf 的 nginx.conf 文件来进行参数配置。调优模块分为三类,全局块、Events 块和 HTTP 块。
(1)全局块,配置文件优化如下:
worker Process_num:4;
worker_cpu_affinity 0001 0010 0100 01000;
(a) worker Process_num 是 Nginx 创建的 worker 进程的个数。Nginx 中基本的网络事件都由 worker 进程处理,所以 worker 进程的数量对 Nginx 的性能会有很大的影响。如果设置太小,则 Nginx 服务器很难应对高并发的请求数量,浪费了资源;如果设置过多会 导 致 进 程 之 间 的 频 繁 切 换 , 造成了不必要的开销 。一 般来说 ,通常将worker Process_num 设置为服务器CPU的内核数量。
(b) worker_cpu_affinity 是为每个 work 进程设置一个固定 CPU 内核。当 Nginx 中的每个worker 进程都处于工作状态时,可能产生多个 worker 进程争抢一个内核的现象,设置 worker_cpu_affinity 可以减少因选择不同 CPU 内核产生的开销。
(2)Events 块,配置文件优化如下:
worker_connections:102400;
use epoll;
Events 块对 Nginx 中事件模块进行配置来控制和处理访问连接。
(a) worker_connections 用来设置每个 worker 进程的最大连接数,最大连接数应与全局块中的 worker File_limit Num 值一样。
(b) use 用来设置事件驱动模型。在不同操作系统下选取的事件驱动模型也有所不同,对于 linux 系统来说,epoll 模型是较为高效的事件管理机制,在性能方面相对于标准事件模型 select 和 poll 要高很多。
(3)HTTP 块主要从网络连接设置、文件缓存设置、Socket 优化设置三部分组成。
HTTP 块是 Nginx 配置的核心部分,对连接处理行为的设置很多都需要在此块中进行设置,其中包括负责负载均衡的 upstream 块,对虚拟主机进行配置的 server 块,以及反向代理location 块等。网络连接设置,配置文件优化如下:
(a) 网络连接超时设置通过设置连接超时时间上限,可以在请求连接超时后,对其进行关闭,将超时连接所占用的系统资源进行释放。在面对高并发数量请求时,可以提供更好的资源利用率和服务效率。
tcp_nodelay on;
SO_REUSEPORT
(4)文件缓存设置,配置文件优化如下:
sendfile 指令指定 Nginx 是否调用 Linux 的系统函数 sendfile()来发送文件。如果服务器用来进行下载等对磁盘 I/O 消耗高的操作,可以设置为 off;如果对于普通应用必须设定为 on,sendfile()函数用以提高文件的发送效率。
open_file_cache 指令用于开启文件缓存功能。 max 为缓存的数量上限,应和worker_connections数量保持一致,inactive 设定一个时间,当文件在此时间内没被请求,则系统会删除缓存。
open_file_cache_valid 用来指定检查缓存有效性的时间间隔。
open_file_cache_min_uses 表示 inactive 时间内文件的最小使用次数,如果小于此值,文件将被删除。
send_file on;
open_file_cache max = 1024 inactive = 30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 3;
(5)Socket 优化设置,配置文件优化如下:
tcp_nodelay 指令开启后,服务器将不会对数据进行缓存。reuseport指令用来设置共享 socket。
reuseport 的设置是用来解决 Nginx 中“惊群”问题。“惊群”问题是指一个连接来临时会唤醒多个进程对其进行抢夺处理。
在连接来临时,多个 worker 线程共享一个套接字,这时便会出现多个线程去抢占资源的情况。传统的 Nginx 在处理这个问题时有两种解决方式:一是配置 accept_mutex on,在 accept()函数调用之前采用锁机制,获得锁的进程才有权对套接字进行处理,但锁机制会影响服务器的性能,另外,这种方式的弊端是所有的 worker 进程都会被唤醒去争夺锁,会对内核资源造成浪费;二是设置 accept_mutex off,这种处理方式虽然少了锁机制,提高了系统响应能力,但会出现“惊群”问题,在 worker 进程数增多时会对系统带来一定性能影响。
tcp_nodelay on;
SO_REUSEPORT
注意:以上这些配置文件仅供参考,根据实际情况去优化。
(6)reuseport 允许多个套接字监听同一端口,图中 80 端口为 HTTP 默认端口,内核能够在套接字中对传入的连接进行负载均衡,自动选择 worker 进程进行处理,而不必唤醒所有 worker 进程。采用此种方式进行 SO_REUSEPORT 配置时,需将 accept_mutex 关闭。配置如下图所示:
在 未 开 启SO_REUSEPORT 配置时,请求来临时,由一个套接字 socket 进行绑定和监听并将连接交给各个进程处理;当开启了 SO_REUSEPORT 配置时,多个进程可以同时绑定和监听同一个TCP/UDP 端口,请求交由哪个进程处理由内核决定,实现了在内核层面的负载均衡。未开启和开启SO_REUSEPORT对比图如下:
5.Linux 内核参数优化
默认的 Linux 内核参数无法满足高并发访问量情况对服务器系统的要求,为了满足特定场景的使用需要同时对 Linux 内核参数进行设置,而且当 Nginx 服务器用于不同目的时,对于 Linux 参数的要求都会有很大的不同。针对以上情况,本文介绍对 Linux 内核参数的优化,使其能够提高 Nginx 对并发请求的服务性能。
Linux 内核参数选项是通过修改/etc 目录下的 sysctl.conf 文件来更改
(1) fs.file--max = 999999 此参数用来限制一个进程可以同时建立的最大连接数。Nginx 服务器通过每个 worker 进程来进行实际的请求响应,所以此参数的设置会影响到 Nginx 的最大并发连接数量。
(2) net.ipv4.tcp_tw_reuse = 1 此参数用来开启重用功能,可以设置为 1 或 0。当设置为 1 时,服务器上处于 TIME_WAIT状态的请求连接会被系统重新建立 TCP 连接。
(3) net.ipv4.tcp_fin_timeout = 10 这个参数是用来设置保持在 FIN_WAIT_2 状态的时间。在一个 TCP 连接关闭过程中,套接字会有一个 FIN_WAIT2 状态到 TIME_WAIT 状态的变化,将此参数设置为 10,可以使套接字更快的进入 TIME_WAIT 状态。
6.总结
本文主要介绍了在CDN与流媒体服务器合作下,当流媒体数据存储在服务器上,是如何处理,主要划分为三大模块,分别为数据处理模块、数据缓存模块、数据发送模块,分别进行了模块的架构设计、模块的主要功能的讲解,特别在数据发送模块中设计了令牌桶算法(这个很重要),对于流量控制很有帮助。欢迎关注,收藏,转发,分享。