测试正在刷新的磁盘缓存缓冲区

时间:2013-11-21 17:13:39

标签: php flush diskcache

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

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

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

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

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

基本上,只是循环,直到至少某些东西已被刷新到文件中,并且filesize至少持续一秒。

我不知道的是,只有当所有文件缓存都已成功刷新到磁盘后,磁盘刷新是否会更新大小;或者它是否会一次刷新几个块,我可能会发现自己试图将部分刷新的文件推送到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);
}

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

长期解决方案将使用AWS Elastic Transcoder,当我可以简单地将原件推送到S3并向Elastic Transcoder提交排队请求时,但还有一段时间了。

2 个答案:

答案 0 :(得分:1)

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

  1. 将数据写入临时文件,然后将其复制/移动到您尝试上传的位置。
  2. 使用两台不同的计算机挂载相同的分区,一台写入文件,另一台尝试上传。
  3. 正在发生某种hacky软件缓冲。
  4. 否则FS缓存应该对操作系统上运行的任何内容完全透明,并且任何未写入磁盘的缓存数据请求都将由操作系统从缓存中提供。

    对于#2,您应该能够通过将缓存方法更改为直写而不是回写来获得稍微。您的写入性能下降,但数据总是立即写入,并且您的数据丢失风险要小得多。

    修改

    Ffmpeg可能会触及您提供的文件名,使用临时文件[s]转换视频,然后将完成的文件移动到目标位置。我假设启动转换的脚本会影响该过程,否则就不会有任何关于是否存在已完成文件的混淆。

    我建议的是,不要将ffmpeg转换为后台进程,然后测试结束文件是否存在fork到后台的另一个PHP脚本,在该脚本中调用ffmpeg 而不用对其进行后台处理, 然后一旦完成就触发上传。

    例如:

    //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返回代码并对其进行操作,而不是想知道为什么某些视频无法无声转换。

答案 1 :(得分:0)

您在这里看到的不是磁盘缓存的影响。磁盘缓存是透明的 - 用户看不到它的行为。

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