-1

我目前有一个视频文件正在通过shell_exec()电话转换为不同的格式。调用或格式转换没有问题,一切正常;但我的下一步是将该文件推送到 s3 存储桶。

但是,我注意到文件系统缓存不一定会立即刷新我新写入的文件,所以我将一个 0 字节文件推送到 s3,即使每当我在文件系统上查看它时它的长度都是正确的。在调用 shell_exec 和 s3-push 之间在我的代码中插入任意 5 秒睡眠解决了这个问题,但感觉非常糟糕,而且我无法知道 5 秒睡眠是否总是足够的,尤其是在使用更大的视频文件和系统正在加载。

我很确定除非我执行同步调用(再次通过 shell_exec),否则我不能强制刷新磁盘缓存,但我不想使用这种方法,因为它会影响服务器上所有带有任何缓冲数据的文件,而不仅仅是我正在操作的单个文件。

所以我写了这段简单的代码来监控文件大小,直到任何磁盘缓存刷新完成:

$prevSize = -1;
$size = filesize($myFileName);
while ($prevSize < $size) {
    sleep(1);
    clearstatcache(true, $myFileName);
    if ($size > 0)
        $prevSize = $size;
    $size = filesize($myFileName);
}

基本上,只是循环直到至少有一些东西被刷新到文件中,并且文件大小已经保持一致至少一秒钟。

我不知道的是,磁盘刷新是否只有在所有文件缓存都成功刷新到磁盘时才会更新大小;或者它是否会一次刷新几个块,我可能会发现自己试图将部分刷新的文件推送到 s3 并最终导致它被损坏。

任何意见,将不胜感激。

编辑

现有代码如下所示:

private static function pushToS3($oldFilePath, $s3FileName, $newFilePath) {
    self::testFileFlush($newFilePath);
    file_put_contents(
        $s3FileName,
        file_get_contents($newFilePath)
    );
}

private function processVidoe($oldFilePath, $s3FileName, $newFilePath) {
    // Start Conversion
    $command = "ffmpeg -i \"$oldFilePath\" -y -ar 44100 \"$newFilePath\"";
    $processID = shell_exec("nohup ".$command." >/dev/null & echo $!");

    self::pushToS3($oldFilePath, $s3FileName, $newFilePath);
    unlink($newFilePath);
    unlink($oldFilePath);
}

这是对在单个服务器上运行的旧遗留代码的修改,只是将文件存储在服务器的文件系统中;但我已经更改了基础设施以在多个 AWS EC2 应用程序服务器上运行以实现弹性,并使用 S3 在 EC2 之间提供文件资源共享。文件由我们的用户上传到应用服务器,然后转换为 flv 并推送到 S3,以便它们可供所有 EC2 实例使用。

长期解决方案将使用 AWS Elastic Transcoder,此时我可以简单地将原始数据推送到 S3 并向 Elastic Transcoder 提交排队请求,但这还需要一段时间。

4

2 回答 2

1

除非您正在执行以下操作之一,否则您所描述的行为应该是不可能的:

  1. 将您的数据写入临时文件,然后将其复制/移动到您尝试上传的位置。
  2. 用两台不同的机器挂载同一个分区,一台写入文件,另一台尝试上传文件。
  3. 某种骇人听闻的软件缓冲正在发生。

否则,FS 缓存应该对操作系统上运行的任何东西完全透明,并且任何对尚未写入磁盘的缓存数据的请求都将由操作系统从缓存中提供服务。

在#2的情况下,您应该能够通过将缓存方法更改为直写而不是回写来绕过它您的写入性能下降,但始终会立即写入数据,并且您面临数据丢失的风险要小得多。

编辑

Ffmpeg 可能正在触摸您给它的文件名,使用临时文件[s] 转换视频,然后将完成的文件移动到目的地。我假设触发转换的脚本使该过程成为背景,否则不会对已完成的文件是否存在产生任何混淆。

我的建议是,不要只将 ffmpeg 分叉到后台进程中,然后测试是否存在最终文件,而是在后台调用 ffmpeg 的另一个 PHP 脚本然后完成后触发上传。

例如:

//user-facing.php
<?php
echo "Queueing your file for processing..."
shell_exec("/usr/bin/php /path/to/process.php /path/to/source.mpg /path/to/dest.mpg &")
echo "Done!"

和:

//process.php
<?php
exec(sprintf("/path/to/ffmpeg -options %s %s", $argv[1], $argv[2]), $output, $exit_code);
if($exit_code === 0) {
  upload_to_s3($argv[2]);
} else {
  //notify someone of the error
}

这还可以让您从 ffmpeg 捕获输出和返回代码并对其采取行动,而不是想知道为什么有些视频只是默默地无法转换。

于 2013-11-21T17:58:07.400 回答
0

您在这里看到的不是磁盘缓存的效果。磁盘缓存是透明的——它的行为对用户是不可见的。

您在这里看到的是创建文件但不立即写入文件的应用程序的行为。您将需要找出其他方法来检查它是否已完成。

于 2013-11-21T18:22:26.020 回答