大数据存储中的文件保留机制

prz*_*och 5 python performance recorder video-recording retention

最近我遇到了 mp4 文件保留的性能问题。我有一个录音机,可以从多个 RTSP 流中保存 1 分钟长的 mp4 文件。这些文件存储在文件树中的外部驱动器上,如下所示:

./recordings/{camera_name}/{YYYY-MM-DD}/{HH-MM}.mp4
Run Code Online (Sandbox Code Playgroud)

除了视频文件之外,该驱动器上还有许多其他文件不予考虑(除非它们具有 mp4 扩展名),因为它们占用的空间要少得多。

文件保留的假设如下。每分钟,负责记录的 python 脚本都会检查外部驱动器的履行级别。如果级别高于 80%,它将扫描整个驱动器,并查找 .mp4 文件。扫描完成后,它会按创建日期对文件列表进行排序,并删除与摄像机编号相同的最旧文件的数量。

负责文件保留的代码部分如下所示。

./recordings/{camera_name}/{YYYY-MM-DD}/{HH-MM}.mp4
Run Code Online (Sandbox Code Playgroud)

/home是外部驱动器安装点)

问题是,当我使用 256 或 512 GB SSD 时,这种机制曾经发挥过作用。现在我需要更大的空间(更多的摄像头和更长的存储时间),并且需要花费大量时间在更大的 SSD 上创建文件列表(从现在的 2 到 5 TB,将来可能是 8 TB)。扫描过程花费的时间远远超过 1 分钟,可以通过减少执行次数并延长“要删除”文件列表的长度来解决这个问题。真正的问题是,该进程本身使用了大量的 CPU 负载(通过 I/O 操作)。整个系统的性能下降是显而易见的。其他应用程序,例如一些简单的计算机视觉算法,运行速度较慢,CPU 负载甚至会导致内核恐慌。

我使用的硬件是 Nvidia Jetson Nano 和 Xavier NX。正如我上面所描述的,这两种设备都存在性能问题。

问题是您是否知道一些适用于我描述的情况的文件保留算法或开箱即用软件。或者也许有一种方法可以重写我的代码,使其更加可靠和执行?

编辑:

我能够os.walk()通过限制检查空间来降低影响。现在我只需扫描/home/recordings以及/home/recognition/较低的目录树(用于递归扫描)。同时,我添加了 .jpg 文件检查,所以现在我从 .mp4 和 .jpg 中查看。这个实现的结果要好得多。

不过,我还需要进一步优化。我准备了一些测试用例,并在 1 TB 驱动器上进行了测试,该驱动器已填充 80%(主要是媒体文件)。我在下面附上了每个案例的分析器结果。

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:
        # no files to delete
        pass
Run Code Online (Sandbox Code Playgroud)

方法6

@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])
Run Code Online (Sandbox Code Playgroud)

方法7

同一数据集上的原始实现持续约 100 秒

编辑2

@norok2提案比较

我将它们与上面的方法6和方法7进行了比较。我尝试了几次,结果相似。

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
Run Code Online (Sandbox Code Playgroud)

方法7 ( glob()) 方法7

iglob() 伊格洛布

赛通 赛通

Uts*_*aan 0

您可以使用该subprocess模块直接列出所有 mp4 文件,而无需循环遍历目录中的所有文件。

import subprocess as sb
oldest_files = sb.getoutput("dir /b /s .\home\*.mp4").split("\n")).sort(lambda fn: os.stat(fn).st_mtime,)[:len(camera_devices)]
Run Code Online (Sandbox Code Playgroud)