经过更多研究,我得出以下结论:
我的第一次计算是使用 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.'?GoogleAccessId=XXXXXXX@developer.gserviceaccount.com&Expires='.$expires.'&Signature='.$signature);
}
执行时间:0.0007929801940918
这改变了一切,因为运行 2000 次 PHP 代码迭代仍然只给我 1.0643119812012 的执行时间加上额外的 0.0325711573357 用于创建所有 m3u8 文件加上 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]) PHP 代码的 868,961 次迭代,总运行时间为 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 生成)。在做出最终决定之前,两者都需要进行查看和比较。
虽然,可以绑定到 m3u8 的 Cloud Storage API 中的新 ACL(例如,以 m3u8 作为有效负载的媒体部分文件)将使一切顺利进行...有什么地方我可以提出这个建议给 Google 存储团队?
-- 30/10 编辑:最终解决方案--
这是我想出的最终解决方案,目前看来运行良好。
设置:
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 文件复制到附加硬盘上的正确目录
nginx.conf 中的新服务器块将 .m3u8 文件解析为 PHP
1.- OSMF播放器请求主m3u8,JS添加会话令牌
2.- PHP 检查会话令牌 + IP 以验证用户
3.- 如果验证,回显当前视频 m3u8
4.- 如果未通过验证,则会回显 m3u8 说您不允许观看此视频
对于 2:44:08 的视频文件,该过程需要 0.7 - 0.9 秒,用户几乎看不到。对于较短的视频,它是指数级的。
云存储桶 (mp4domain) - mp4.domain.com
存储桶应用了一个默认 ACL,该 ACL 将所有文件设为私有但可供用于生成签名 URL 的 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 文件,因此不必在客户端进行黑客攻击。
希望这可以帮助有类似问题的人。