Jetson平台大容量存储录像留存机制性能优化咨询
近期在MP4文件留存功能上遇到性能问题。部署的录像程序可从多路RTSP流中保存时长为1分钟的MP4文件,文件存储在外置驱动器中,目录结构如下:
./recordings/{camera_name}/{YYYY-MM-DD}/{HH-MM}.mp4
除视频文件外,该驱动器还存储了大量其他占用空间极小的文件,留存机制仅处理扩展名为.mp4的文件,其余文件不做操作。
原有留存规则与实现
文件留存规则:负责录像的Python脚本每分钟检测一次外置驱动器的空间占用率,若占用率超过80%,则扫描全驱动器查找所有.mp4文件;扫描完成后按文件修改时间(st_mtime)对文件列表排序,删除数量与接入摄像头总数相等的最旧文件。
原有实现代码段如下(/home为外置驱动器挂载点):
import shutil, os, logging total, used, free = shutil.disk_usage("/home") used_percent = int(used / total * 100) if used_percent > 80: logging.info("SSD usage %s. Looking for the oldest files", used_percent) try: oldest_files = sorted( ( os.path.join(dirname, filename) for dirname, dirnames, filenames in os.walk('/home') for filename in filenames if filename.endswith(".mp4") ), key=lambda fn: os.stat(fn).st_mtime, )[:len(camera_devices)] logging.info("Removing %s", oldest_files) for oldest_file in oldest_files: os.remove(oldest_file) logging.info("%s removed", oldest_file) except ValueError as e: # 无文件可删除时跳过 pass
该机制在256GB或512GB SSD上运行效果良好,但扩容到2TB~5TB容量SSD(未来可能扩容至8TB)以接入更多摄像头、延长存储周期时,生成待处理文件列表耗时远超1分钟。
核心痛点:扫描过程产生大量IO操作,CPU负载极高,导致全系统性能下降,运行计算机视觉算法等其他应用时处理速度明显变慢,CPU负载过高甚至会触发内核恐慌(kernel panic)。所用硬件平台为Nvidia Jetson Nano和Xavier NX,两款设备均存在该问题。
核心诉求:是否存在适用于该场景的文件留存算法或开箱即用软件?是否可通过重写现有代码提升机制的可靠性与运行性能?
第一次优化进展
已通过缩小扫描范围降低os.walk()的性能影响,目前仅递归扫描/home/recordings和/home/recognition/目录,大幅缩小递归遍历的目录树规模;同时新增.jpg文件检测逻辑,留存机制会同时查找.mp4与.jpg文件,该版本性能已有明显提升,但仍需进一步优化。
在填充率80%的1TB驱动器(存储内容以媒体文件为主)上开展测试,两个测试用例信息如下:
测试用例 method6
import os @time_measure def method6(): paths = [ "/home/recordings", "/home/recognition", "/home/recognition/marked_frames", ] files = [] for path in paths: files.extend(( os.path.join(dirname, filename) for dirname, dirnames, filenames in os.walk(path) for filename in filenames if (filename.endswith(".mp4") or filename.endswith(".jpg")) and not os.path.islink(os.path.join(dirname, filename)) )) oldest_files = sorted( files, key=lambda fn: os.stat(fn).st_mtime, ) print(oldest_files[:5])

测试用例 method7
import glob, os @time_measure def method7(): ext = [".mp4", ".jpg"] paths = [ "/home/recordings/*/*/*", "/home/recognition/*", "/home/recognition/marked_frames/*", ] files = [] for path in paths: files.extend((file for file in glob(path) if not os.path.islink(file) and (file.endswith(".mp4") or file.endswith(".jpg")))) oldest_files = sorted(files, key=lambda fn: os.stat(fn).st_mtime) print(oldest_files[:5])

原始实现在相同数据集上的运行时长约为100秒。
第二次优化对比测试
针对@norok2提出的方案,与前文method6、method7做对比测试,多次测试结果相近:
Testing method7 ['/home/recordings/35e68df5-44b1-5010-8d12-74b892c60136/2022-06-24/17-36-18.jpg', '/home/recordings/db33186d-3607-5055-85dd-7e5e3c46faba/2021-11-22/11-27-30.jpg', '/home/recordings/acce21a2-763d-56fe-980d-a85af1744b7a/2021-11-22/11-27-30.jpg', '/home/recordings/b97eb889-e050-5c82-8034-f52ae2d99c37/2021-11-22/11-28-23.jpg', '/home/recordings/01ae845c-b743-5b64-86f6-7f1db79b73ae/2021-11-22/11-28-23.jpg'] Took 24.73726773262024 s _________________________ Testing find_oldest ['/home/recordings/35e68df5-44b1-5010-8d12-74b892c60136/2022-06-24/17-36-18.jpg', '/home/recordings/db33186d-3607-5055-85dd-7e5e3c46faba/2021-11-22/11-27-30.jpg', '/home/recordings/acce21a2-763d-56fe-980d-a85af1744b7a/2021-11-22/11-27-30.jpg', '/home/recordings/b97eb889-e050-5c82-8034-f52ae2d99c37/2021-11-22/11-28-23.jpg', '/home/recordings/01ae845c-b743-5b64-86f6-7f1db79b73ae/2021-11-22/11-28-23.jpg'] Took 34.355509757995605 s _________________________ Testing find_oldest_cython ['/home/recordings/35e68df5-44b1-5010-8d12-74b892c60136/2022-06-24/17-36-18.jpg', '/home/recordings/db33186d-3607-5055-85dd-7e5e3c46faba/2021-11-22/11-27-30.jpg', '/home/recordings/acce21a2-763d-56fe-980d-a85af1744b7a/2021-11-22/11-27-30.jpg', '/home/recordings/b97eb889-e050-5c82-8034-f52ae2d99c37/2021-11-22/11-28-23.jpg', '/home/recordings/01ae845c-b743-5b64-86f6-7f1db79b73ae/2021-11-22/11-28-23.jpg'] Took 25.81963086128235 s
各方案性能分析截图:
- method7(
glob())方案:
iglob()方案:
- Cython方案:

内容的提问来源于stack exchange,提问作者przemoch

