经过更多研究,我得出以下结论:
我的第一次计算是使用 Google 的 gsutil 工具完成的,该工具在计算签名 URL 哈希时似乎会引入大量开销,例如:
gsutil 代码:
gsutil signurl -d 60m /path/to/google.p12 gs://bucket/file
执行时间:0.73812007904053
,但是,使用本机 PHP 函数创建签名 URL 要快得多:
PHP代码:
function storageURL($bucket,$archivo) {
$expires = time()+60;
$to_sign = ("GET\n\n\n".$expires."\n/".$bucket.'/'.$archivo);
$fp = fopen('/path/to/google.pem', 'r');
$priv_key = fread($fp, 8192);
fclose($fp);
$pkeyid = openssl_get_privatekey($priv_key);
if(!openssl_sign($to_sign,$signature,$pkeyid,'sha256')) {
$signature = 'sinfirma';
} else {
$signature = urlencode(base64_encode($signature));
}
return ('https://'.$bucket.'.storage.googleapis.com/'.$archivo.'[email protected] /cdn-cgi/l/email-protection&Expires='.$expires.'&Signature='.$signature);
}
执行时间:0.0007929801940918
这改变了一切,因为运行 2000 次 PHP 代码迭代仍然只给我 1.0643119812012 的执行时间,加上用于创建所有 m3u8 文件的额外 0.0325711573357 加上 0.0039050579071045 的额外 6 次迭代来为 m3u8 创建签名 URL;总执行时间为 1.100788196444004 秒,其中最大部分取决于视频的长度。
这实际上看起来很好,因为用户习惯了较长视频的较长“加载”或“缓冲”时间,因此当视频较长时大约 0.5 - 大约 1.5 秒的额外时间不会对可用性产生太大影响。
顺便说一句,在当前状态下,服务器上目前有 689 个视频,总共有 864,138 个相关的 .ts 和 .aac 文件,每个视频有 6 个 m3u8 (180,360,480,720,1080,AAC) 加上一个额外的 m3u8 主文件播放列表...因此,为所有视频生成每小时的 url 将需要 (689 [master m3u8] + 864,138 [assets] + 4134 [qual m3u8]) 868,961 次 PHP 代码迭代,总运行时间为 467.15262699127(约 7 分钟),考虑到动态生成每个 URL 的运行时,这是可以管理的,但没有实际意义。
这一切都使用 Google Compute n1-highmem-2 实例,该实例不是那么强大,因此切换到更强大的机器将使所有这一切变得更快。
但所有这些都带来了另一个维度,因为谷歌(就像所有其他公司一样)对每个存储桶上的每次 PUT 操作收费,因此成本计算是有序的。查看上个月的统计数据,我看到总共 447,103 次视频播放(嘿,这是一个小网站),根据提议的方案,将为每个视频点击生成 7 个 PUT 操作(6 比特率 m3u8 + 1 master m3u8),该月总共有 3,129,721 个额外的 PUT,计算成本(3129721 / 10000 * 0.01)给我一个 3.13 美元的额外成本……虽然很小,但如果该网站变得更受欢迎,可能会成为一个问题。另一个解决方案(每个人每小时签名的 URL)将生成 ((689 [master m3u8] + 4134 [qual m3u8]) * 24 [gens per day] * 30 [days per Month]) 3,472,560 个额外的 PUT...这大约是相同,所以我在两个方案之间进行选择时处于或接近收支平衡点(成本方面)。我必须使用前几个月的数据在这里做更多的数字,以便更好地了解这一点,因为一种方案(每次点击的 URL)取决于用户数量,另一种方案(全局 URL 生成)取决于视频数量......并且它们各自以完全不同的方式扩展。
本质上,使用本机代码,问题似乎纯粹是金钱上的小编码向量(重写视频播放代码与引入每小时 URL 生成)。在做出最终决定之前,需要对两者进行研究和比较。
虽然,Cloud Storage API 中的一个新 ACL(例如以 m3u8 作为有效负载的媒体部分文件)可以绑定到 m3u8,这将使一切工作更顺利……我可以在某个地方向 Google 提出这个建议吗?存储团队?
-- 30/10 编辑:最终解决方案 --
这是我想出的最终解决方案,到目前为止似乎运行良好。
Setup:
Google 云计算实例上的 Nginx - m3u8.domain.com
视频转换器执行以下操作:
1.- ffmpeg将源文件转换为180,360,480,720,1080,AAC子文件
2.- ffmpeg 将文件分割成 11 秒的块(文件较少,iOS 仍然接受)
3.- PHP 将所有媒体文件复制到 GS 存储桶
4.- PHP解析生成的m3u8文件并创建动态m3u8文件
5.- PHP 将 size.m3u8 文件和 master.m3u8 文件复制到附加 HDD 上的正确目录
nginx.conf 中的新服务器块将 .m3u8 文件解析为 PHP
1.- OSMF播放器请求master m3u8,JS添加会话令牌
2.- PHP 检查会话令牌 + IP 来验证用户
3.- 如果经过验证,则回显当前视频 m3u8
4.- 如果未验证,则回显 m3u8 表示不允许您观看此视频
对于 2:44:08 的视频文件,该过程需要 0.7 - 0.9 秒,用户几乎看不到。对于较短的视频来说,它是指数级的小。
云存储桶 (mp4domain) - mp4.domain.com
该存储桶应用了默认 ACL,该 ACL 使所有文件均为私有文件,但可供用于生成签名网址的 Google ID 访问。
因此,单个视频具有以下文件:
SERVER/nginx/mp4/uniqid/uniqid.m3u8
SERVER/nginx/mp4/uniqid/180p/stream.m3u8
SERVER/nginx/mp4/uniqid/360p/stream.m3u8
SERVER/nginx/mp4/uniqid/480p/stream.m3u8
SERVER/nginx/mp4/uniqid/720p/stream.m3u8
SERVER/nginx/mp4/uniqid/1080p/stream.m3u8
SERVER/nginx/mp4/uniqid/audio/stream.m3u8
GS/bucketmp4/uniqid/180p/segment##.ts
GS/bucketmp4/uniqid/360p/segment##.ts
GS/bucketmp4/uniqid/480p/segment##.ts
GS/bucketmp4/uniqid/720p/segment##.ts
GS/bucketmp4/uniqid/1080p/segment##.ts
GS/bucketmp4/uniqid/audio/segment##.aac
(所以似乎认为这是代码,否则不会让我格式化它)
这样,对 GS 的写入只需完成一次,并且由于所有客户端都认为他们正在接收纯 m3u8 文件,因此无需在客户端进行黑客攻击。
希望这可以帮助有类似问题的人。