我有一个视频门户网站,我想根据管理员中的视图,分辨率和文件大小计算视频传递的传出流量。我的问题是如果我的视频视图表中有很多行,php正在退出,内存限制致命错误(512M内存限制)。现在我需要最佳实践或最佳解决方案来计算/处理它。
这就是我的视频观看表:
|----vwid----|--vid--|--------resolution--------|
|Videoview ID|VideoID|Resolution of viewed video|
(有3个与此问题列无关)
每个视频和分辨率的文件大小都不同,需要从每个stat()的文件系统中获取,这就是为什么我不能只拿一个并将它与视图的数量相乘。
在获取每一行并添加单个文件的文件大小之后,我的下一次尝试只获取每个连续的固定行数(如10'000)。但这并没有采取与第一次尝试不同的方式。
之后我尝试计算每个视频的每个分辨率的视图,但这导致了一个非常慢的查询(35s),我放弃了这个想法。
目前我的视图表中有300万行用于测试目的(它们每天都会随机添加),所以我需要一个很好的解决方案来处理大量的行。
现在问题是你们有没有想过要做得更好?如果您需要更多信息,请不要犹豫。
解释查询:
SELECT vid, resolution, COUNT(*) FROM videoviews GROUP BY vid, resolution
输出:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE anitube_videoviews ALL NULL NULL NULL NULL 3126686 Using temporary; Using filesort
答案 0 :(得分:4)
首先,你应该考虑一种不同的方法。您的解决方案将根据潜在视图计算结果 - 所以如果我刷新页面5次(对于1GB视频文件),我会在一瞬间产生5 GB的流量 - 我没有。
按照彼得的建议存储视图持续时间更好 - 但仍然不准确。该文件可能已经完全下载,但用户只查看了3分钟。所以你会追踪更少的流量。
因此,您应该跟踪转移到客户端计算机的实际字节的字节,而不是依赖于分辨率和viewcount或view-duration,以获得准确的结果。
实现此目的的一种可能方法是避免文件上的直接链接,但使用php脚本文件传递它们,该文件可以跟踪传输的卷。
以下代码段将提供此类功能。请注意,对于拥有大量用户的服务器,您不应该使用如此大的块大小 - 或者您将很快耗尽内存: - )
以下文件可以存储为getFile.php
,并通过传递文件ID来调用,如getFile.php?id=25565
。 (拥有这样的getFile.php
还具有以下优势:您无需将文件显示为到您的网络 - 在getFile.php
中,您可以再次检查登录信息,以及限制未经授权的访问。)
$file = resolveIdToActualFilePath($_GET["id"]);
set_time_limit(0);
//Important: we catch that manually to determine transfered bytes.
ignore_user_abort(true);
ini_set('output_buffering', 0);
ini_set('zlib.output_compression', 0);
header('Content-Description: File Transfer');
header('Content-Type: video/mp4'); //set depending on format.
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
// Repeat reading until EOF
$chunk = 1024 * 1024; // bytes per chunk (1 MB)
$fh = fopen($file, "rb");
while (!feof($fh)) {
echo fread($fh, $chunk);
flush();
ob_flush();
//catch user abort manually.
if (connection_status() != 0){
//abort or timeout. Store already transfered amount to database.
//here an error of one time chunk size might appear, cause it has been read, but not delivered.
file_put_contents("test.txt", "Aborted after: ".(ftell($fh)+1)." Bytes.");
fclose($fh);
exit;
}
}
//pointer pos + 1 = actual bytes transfered - write to database.
$bytesTransfered = ftell($fh) +1;
file_put_contents("test.txt", "Download complete after ".$bytesTransfered." Bytes");
fclose($fh);
exit;
根据您存储转移字节的方式,查询变得非常简单 - 而且速度很快。
我建议您使用这样的表格来维护评估所需的所有信息:
id | fileId | userId | bytes | dateTimeStart | dateTimeEnd | status
1 2256 158 15454 2014-12-27 18:45:20 2014-12-27 18:52:17 COMPLETE
2 1123 122 185 2014-12-27 19:00:00 2014-12-27 19:00:02 ABORT
3 12355 112 13365 2014-12-27 20:45:20 2014-12-27 20:45:36 COMPLETE
这样可以确定哪些文件的中止频率,平均下载量是多少 用户的速度(假设您的服务器不是瓶颈),在给定时间内您的峰值上传率是多少,平均负载是多少等。
将表格编入索引,这样的查询应该立即运行:
SELECT SUM(bytes) WHERE fileId = 1123; --traffic per file
SELECT SUM(bytes) WHERE userId = 189; -- traffic per user
SELECT SUM(bytes) WHERE DATE(dateTimeStart) = CURDATE(); -- traffic today
SELECT SUM(bytes) WHERE fileId = 1123 AND DATE(dateTimeStart) = CURDATE(); -- traffic today for file 1123.
SELECT SUM(bytes) WHERE dateTimeStart >= DATE_SUB(NOW(), INTERVAL 7 DAY): -- traffic within last 7 days.
在bytes列上使用(无符号)Bigint可以将流量加总到9223372036854775807
个字节,即8 ExaBytes。 (8192 PetaByte)(目前全球互联网流量为每月27,48 PetaByte - 所以除非你主持整个互联网,否则你应该会好一段时间:))
答案 1 :(得分:0)
这个问题可能有几种方法:
视频表中的商店规模
我看到VideoID
列,这意味着你有视频表,你可以添加列size default 0
并创建简单的php脚本来填充它,如下所示:
set_time_limit(0);
do {
data = 'select * from `videos` where `size` = 0 limit 1000'; // select any reasonable limit here
foreach row in data {
file_size = fstat(filename)
update `videos` set `size` = ??? where `videoid` = ???
}
} while (sizeof(rows) > 0);
检查您是否有索引:
然后您将能够运行如下查询:
select sum(a.`size`) as totalsize
from `videos` as a inner join `videoviews` as b on (a.`videoid` = b.`videoid`)
当然,在上传新视频或更改旧视频时 - 您需要将size
更新为实际视频
保存实际汇总统计信息
您可以创建单独的表,存储实际流量,如下所示:
create table `stats` (
`resolution` varchar(...) primary key,
`total_size` bigint
);
在每个视图中 - 像
一样更新此表update `stats` set `total_size` = `total_size` + ??? where `resolution` = ???;
当然您会错过旧数据,但您可以使用与第一个解决方案类似的方法填充它(只需在开始统计数据之前选择所有视图)
PS。在任何情况下,我建议你填充视频表大小,以避免文件系统查询
答案 2 :(得分:0)
我认为您应该在该表中添加一个view_duration字段,并运行如下查询:
SELECT resolution, SUM(view_duration) FROM videoviews WHERE vwid>0 GROUP BY resolution
以上内容应该为您提供每个分辨率的所有观看次数的总时间。对于每种分辨率和视频格式,您的传出流量将是bytes_per_second * sum_of_duration_of_view(以秒为单位)。 https://documentation.apple.com/en/motion/usermanual/index.html#chapter=B%26section=2%26tasks=true