我目前有一个视频文件正在通过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提交排队请求时,但还有一段时间了。
答案 0 :(得分:1)
除非您正在执行以下操作之一,否则您所描述的行为应该是不可能的:
否则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)
您在这里看到的不是磁盘缓存的影响。磁盘缓存是透明的 - 用户看不到它的行为。
您在这里看到的是创建文件但不立即写入文件的应用程序的行为。您需要找出其他方法来检查是否已完成。