文件写入函数write和fwrite对SRS的DVR性能影响的比较

news2024/10/6 3:28:30

概述

     在linux环境中,对于文件进行读写操作的时候,我们可以采用libc提供的fread/fwrite系列的一套函数,也可以采用操作系统提供的read/write系列的一套系统api函数。

     对于libc提供的文件读写函数,首先它可移植性比较好,因为libc为我们屏蔽了操作系统的底层差异,在linux、windows等不同的操作系统环境下面都有标准的接口实现,因此不需要我们为不同的操作系统进行适配。其次,libc提供了带缓冲功能的读写能力,而操作系统底层文件读写API却不提供这种能力,缓冲能力在大多数情况下能够为我们带来文件i/o性能的提升。

      当然libc的文件读写api函数也存在不足之处,缺少了writev/readv之类的函数。不过readv/writev的功能无非就是将多个缓冲区的内容合并成一次批量读写操作,而不需要进行多次API调用,从而减少实际物理I/O的次数,我想libc没有提供这类函数主要也是因为其缓冲功能已经能够将本来需要多次的小块物理I/O操作合并成了一次更大块的物理i/o操作,所以就没有必要再提供readv/writev了。

      在应用SRS的视频DVR录存功能进行压力测试的时候,我就碰到了原生SRS在进行录存的时候大并发量文件写入导致CPU消耗过大的问题。究其原因,是因为SRS进行录存文件写入操作的SrsFileWriter类采用了操作系统提供的系统文件写入函数write,它没有缓冲功能,导致DVR录制的时候大量音视频碎片数据写入引起大量的系统调用,可能引起系统在内核态和用户态进行大量迁移,从而引起CPU消耗过高的问题。

     下面就测试的原理和方法、测试的环境、测试的结果和相关的结论和大家进行分享。

测试的原理和方法

        压测工具,用srs_bench套件中的sb_rtmp_publish模拟推流客户端进行大并发量推流模拟,一台机器压测能力不够可以开启多台机器进行压测。

在srs上面开启DVR录存功能,在srs的配置文件中添加如下代码:

 vhost __defaultVhost__ {
 •    dvr {
 •        enabled      on;
 •        dvr_path     /data/ssd/[app]/[stream].[timestamp].ts;
 •        dvr_plan     session;
 •    }
 }

       启动srs后,用压测工具进行压测,观察测试过程中的CPU、网络IO、磁盘IO相关数据,并进行对比。

测试环境

     SRS dvr服务器配置如下:

  • CPU: INTEL Xeon 4110 双路16和32线程

  • 内存:32G

  • 网卡:10Gb

  • 磁盘:两块980G的SSD盘做成RAID0(可用空间共1.8T)

  • 操作系统:CentOS 7.6。

       这里需要说明一下,采用SSD盘主要是为了确保磁盘性能足够,以确保能够支撑大的并发压力,从而在大并发压测的情况下观察系统性能情况,如果本身磁盘I/O性能比较低下,大量的I/O等待可能导致观察不到CPU瓶颈的现象。

      另外,在我的测试环境中,SRS经过了多进程改造,能够支持推流进来后自动将不同的流均衡到不同的SRS进程上面,从而能够充分利用服务器多核的能力,但是由此得出的结论同样适合于单进程SRS。

测试过程

  1. SRS使用write文件写入SSD盘操作进行压力测试,压测1000路并发3M码流的视频并记录测试结果。

  2. 改写SRS代码,使用fwrite文件写入SSD盘操作进行压力测试,压测1000路并发3M码流的视频并记录测试结果。

  3. 重复1的过程,将写入SSD盘改成写内存盘进行压力测试,其他不变。

  4. 重复2的过程,将写入SSD盘改成写内存盘进行压力测试,其他不变。

需要说明一下,由于我手上的服务器只有32G内存,只能分配16G内存给内存盘使用,

采用如下命令挂载内存盘:

  mkdir /data/tmp 
  mount -t tmpfs -o size=16G,mode=0755 tmpfs /data/memdisk

并且修改srs的配置文件将文件写入到内存盘:

 vhost __defaultVhost__ {
     dvr {
         enabled      on;
         dvr_path     /data/memdisk/[app]/[stream].[timestamp].ts;
         dvr_plan     session;
     }
 }

由于内存盘比较小,按照3Gb的写入速度,最多能写42s的DVR。

测试数据

测试1:write写入ssd盘

     从上图可以看到,1000路3M的DVR录制已经将系统的CPU都跑满了,特别需要关注的是cpu的时间主要消耗在了内核空间上面,占了87.5%。

      用nload查看当时的输入带宽情况,发现系统输入带宽平均只有2.17Gb,没有达到预期的3Gb的带宽,应该是CPU负载过高导致SRS来不及处理网络I/O引起的性能下降。

      用perf工具对其中一个srs 进程进行性能采样分析,得到下面的火焰图:

         可以发现,sys_write操作占用的时间消耗是最多的,对比上面用top看到的内核态消耗的时长占比可以得出的结论是一致的。

最后看磁盘I/O情况:

 

      从上图看磁盘的利用率没有到100%,虽然有一定的波动,但是总体上还是在合理的可以接受的性能范围内。

测试2:fwrite写入ssd盘

 

     从上图可以看到,1000路3M的DVR录制已经将系统的CPU整体来说还有很多空闲(这里说明一下,部分进程的SRS占比高的原因是因为当时任务分配的不够均衡引起的)。特别值得注意的是本次测试内核时间占比大幅下降,只有9.1%。

    再用nload看网络i/o情况,如下图:

 

    网络i/o相当平稳,和预期的3Gb完全吻合。

    再看磁盘i/o的情况:

 

     从上图看磁盘的利用率没有到100%,虽然有一定的波动,但是总体上还是在合理的可以接受的性能范围内。

     最后看火焰图:

    

      系统调用的时间占比大幅度缩短了,在上图几乎找不到sys_write的位置了。

测试3:write写入内存盘

      从CPU的情况看,采用内存盘也比较理想,load average只有 7.5,性能非常理想。

 

测试4:fwrite写入内存盘

      对比测试3的CPU情况,可以看到CPU内核时间有更进一步缩短, load-average也有明显变小,相比测试3的性能更好。

 

     测试3和测试4的nload图和测试2基本一致,不再贴出。

测试结论

    从以上4个测试可以得出以下结论:

  1. 无论ssd盘还是内存盘,采用fwrite的性能比采用write的性能有明显的提升,其主要得益于fwrite内置的缓存功能减少了系统调用的数量,带来内核时间消耗的减少,从而提升了性能。

  2. 在ssd盘情况下,fwrite的缓冲能力可以大幅度降低对于CPU的消耗,但是在采用内存盘的情况下,CPU的消耗虽然也能够降低,但是不是那么明显。

存在的疑问:

    之前想当然地认为用write写内存盘,因为系统调用引起的用户态到核心态的切换还是会导致cpu大量消耗,一样会导致CPU消耗高居不下,但是事实看到是采用内存盘以后cpu消耗明显下降了,是不是可以认为系统调用引起的用户态到核心态的切换消耗实际上并没有想象的那么大,而是内核态在处理小块的文件write写入磁盘的时候还存在着其他因素引起消耗大量的cpu。譬如,因为最终写入磁盘都是按照扇区写入的,而小块写入需要操作系统将这个小块对齐并填充到一个完整的磁盘扇区,从而引起性能大幅下降,而内存盘是不是就不会存在这个问题?由于我自己没有内核方面的经验,所以只能存疑了,也请懂内核的朋友给予指点。

对于未来的展望

    不管SRS也好,还是NGINX也好,虽然前者采用st-thread框架的协程能力来实现网络异步i/o,但是和后者一样,最终还是采用epoll事件循环来实现网络异步i/o的,但是对于文件i/o,目前存在的问题是,无论是write还是fwrite都是同步操作,在磁盘请求比较繁忙的情况下,必然会导致进程或者线程阻塞,从而引起系统并发性能的下降。

     由于操作系统本身不支持epoll异步(linux下的ext4本身没有实现poll的回调),所以寄希望于epoll来实现文件i/o的异步操作是行不通的。NGINX对于文件异步i/o采用了aio+多线程的方式来实现的,个人感觉是由于和epoll模型来说是一套独立的框架,还是相对比较复杂。

    不过,好在linux在5.1内核以后提供了io_uring的异步i/o框架,它可以统一网络i/o和磁盘i/o的异步模型,并支持buffer IO,值得我们去关注学习一下,也值得我们后面一起去探讨一下未来如何在srs上采用io_uring来实现带有fwrite一样的缓冲能力的磁盘i/o的操作,来彻底解决磁盘i/o引起的性能瓶颈的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/146779.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言实现插入排序和希尔排序(动态图演示过程)

插入和希尔插入排序时间和空间复杂度分析希尔排序时间和空间复杂度分析本篇文章将插入排序和希尔排序放在一起讲解,是因为后者可以说是前者的排序方式的一种优化,思路上大体一样,插入和希尔在整个排序的大章节中,算是比较简单的&a…

java食堂库存管理系统源码

简介 Java基于sprinboot开发的食堂库存管理系统,用于统计食堂库存的,包含采购、入库、出库、折损等功能。 演示视频 https://www.bilibili.com/video/BV1Jf4y1C7vq/?share_sourcecopy_web&vd_sourceed0f04fbb713154db5cc611225d92156 调试 https…

php宝塔搭建部署实战响应式儿童益智玩具网站模板源码

大家好啊,我是测评君,欢迎来到web测评。 本期给大家带来一套php开发的响应式儿童益智玩具网站模板源码,感兴趣的朋友可以自行下载学习。 技术架构 PHP7.2 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&am…

java基于ssm空气质量检测系统源码网站空气质量监测源码

简介 Java基于ssm的空气质量检测系统,检测设备检测一定范围内的企业空气指数,如果有污染则地图显示红色标记。 演示视频 https://www.bilibili.com/video/BV1GK4y1W7JB/?share_sourcecopy_web&vd_sourceed0f04fbb713154db5cc611225d92156 技术 …

67、NeRF-Editing: Geometry Editing of Neural Radiance Fields

简介 允许用户对场景的隐表示进行可控的形状变形,在不重新训练网络的情况下合成编辑过的场景的新视图图像。在提取的显式网格表示(Mesh)和目标场景的隐式神经表示之间建立了对应关系,利用基于网格的变形方法(ARAP)对场景的网格表…

CAN 协议及标准规格

文章目录CAN协议对应ISO/OSI 基本参照模型ISO 标准化的 CAN 协议通信速度和最大总线长度的关系根据协议不同选择对应IC其他标准规格CAN协议对应ISO/OSI 基本参照模型 CAN 协议中关于 ISO/OSI 基本参照模型中的传输层、数据链路层及物理层 数据链路层分为 MAC 子层和 LLC 子层…

Vue3基础知识,看这篇文章就够啦~

0 前言整理了一下自己在学Vue3的时候的笔记,如果有错误的地方还望指正~1 setup函数1.1 参数 setup(props,context)props:父组件传递过来的属性context:SetupContext,即是setup函数的上下文1.1.1 参数1 props如果想在setup函数中使…

脑电项目探索和实现(EEG) (上):研究数据集选取和介绍SEED

数据集介绍: 使用上海交大的SEED数据集1 SEED数据集包含12名受试者的脑电图和眼动数据以及另外3名受试者的脑电图数据。数据是在他们观看电影片段时收集的。电影片段是精心挑选的,以诱导不同类型的情绪,积极的,消极的&#xff0…

BI技巧丨子类Top及其他

BOSS:白茶,能不能在展示产品销量的时候,前三的展示,其他的都归为“其他”啊? 白茶:可以啊!安排! 在实际项目中,一张Dashboard看板的设计,既要考虑逻辑的准确无…

Spring中@Conditional注解详解

文章目录Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。首先创建Dog类然后创建MyCondition类定义两个Bean测试方法AnnotationConfigApplicationContext测试ConditionalOnBean和ConditionalOnMissingBean注…

51单片机学习笔记_8 IICAT24C02 芯片的应用

I2C EEPROM I2C I2C(Inter-Integrated Circuit)总线是由 PHILIPS 公司开发的两线式 串行总线,用于连接微控制器及其外围设备。 I2C 结构 I2C 只有两根双向信号线,一根是 SDA 数据线,一根是 SCL 时钟线。…

2-选择题练手

1.HASH函数冲突处理方式不包括以下哪一项 A.开放定址法 B.链地址法 C.插入排序法 D.公共溢出区发 答:C 析: HASH函数冲突处理方式有: 开放定址法:(线性探测再散列,二次探测再散列,伪随机…

Netty进阶——粘包与半包(固定分隔符方式解决粘包问题)

目录一、固定分隔符方式解决粘包问题(代码示例)1.1、固定分隔符解决粘包问题的服务端代码示例1.2、固定分隔符方式解决粘包问题的客户端代码示例1.3、分别启动服务端,客户端,查看服务端结果输出一、固定分隔符方式解决粘包问题&am…

vitepress(四):引入vue组件

这节课的内容需要有前置的良好的Vue基础,如果你仅仅想搭建一个存放md文件的网站的话,可以不必学习后面的内容,当然如果你想个性化自己的站点,那么推荐你学习一下引用的方式和注意点,开始你的个性化之旅 编写VUE组件 …

ARES Map地理信息系统(GIS)

ARES Map地理信息系统(GIS) ARES地图是GRAEBERT的地理信息系统(GIS)产品。该软件是一个复合解决方案,它将GIS的知识和内容放在一个CAD丰富的DWG系统上,并允许您同时使用它们。该软件的地图和设计将以DWG格式自然存储,但它们也可以包含GIS信息…

【阶段三】Python机器学习02篇:机器学习项目流程

本篇的思维导图: 机器学习项目流程 大致分为以下6个环节: (1)项目背景(问题定义) (2)数据收集 (3) 数据预处理与探索性数据分析 (4) 特征工程 (5)构建模型:机器学习模型(算法)的选择

TCP 慢启动突发丢包

TCP 慢启动会导致持续突发丢包。 慢启动以 y2xy2^xy2x 增加窗口,在 BDP 已经填满时,后续的慢启动过程如下: ​每一个 ACK 触发 2 个 报文,最终至少丢掉 1 个 BDP 的数据后 sender 才能检测到丢包而退出慢启动并进行重传。 这是…

C语言蓝桥杯刷题:明码

题目链接 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 汉字的字形存在于字库中,即便在今天,16*16 点阵的字库也仍然使用广泛。 16*16 点阵的字库把每个汉字看成是 1616 个像素信息。并把这些信息记…

电子书销售是一种可以躺赚的商业模式么?

文章目录前言电子书销售市场规模到底有多大?电子书产业链电子书阅读平台电子书销售平台国外国内其它销售模式探讨创建电子书创建电子书的工具电子书下载好去处相关法规前言 不知何时,有了网赚一词,例如去各大平台撸羊毛薅羊毛,利…

Vector - VT System - 继电器板卡_VT2820

这块板卡应该是我个人最喜欢的板卡了,虽然说有很多的模拟板卡、数字板卡等仿真板卡,但是在实际的应用中,我们仿真还是很难做到绝对的信号一致,但是如果有实际的硬件,通过继电器板卡就很好的模拟实际车上的场景&#xf…