【问题标题】:Google Cloud Storage Signed Url for media用于媒体的 Google Cloud Storage 签名网址
【发布时间】:2014-10-01 03:37:15
【问题描述】:

我建立了一个视频网站,为用户提供 m3u8 和相关的 ts 文件。我不希望媒体文件免费提供,所以我所做的是:当用户在网站上时,会在 mysql 中使用他们的 IP 和令牌创建一个会话;当他们请求特定媒体子域(mp4.domain.com)中的任何文件时,Nginx 身份验证模块使用 url 和附加的令牌作为通过 javascript 设置的请求 cookie 查询 localhost:8080 ...查询数据库并允许/拒绝根据会话信息访问文件。

现在这工作正常,开销在 8 - 20 MS 之间,具体取决于服务器负载,并且在生成 m3u8 链接时无需在 PHP 中破坏 url; OSMF 只是获取 m3u8 并请求文件,javascript 添加令牌 cookie 并且 Bob 是你的叔叔。

现在我们正在迁移到 Google Cloud Storage,而我面临的问题是我无法真正控制其中的任何一个...... m3u8 的签名 url 很容易,但每个 m3u8 都会必须为每个分辨率、缩略图和音频 aac 的每个 ts 文件动态生成签名 url(给你一个想法,我选择的随机视频总共有 1,043 个文件)......这是要生成的 1,043 个不同的签名 url,大约6 个 MS 每个产生 6 秒的总生成时间……这太可怕了。

有没有其他方法来管理这个?我不太热衷于 Cloud Storage API,但我似乎找不到其他任何东西...ACL 似乎对此毫无用处,而我唯一能想到的另一件事是...每天旋转文件位置?...基础以混淆它们。有没有人遇到过类似的情况或知道我可以从哪里开始解决这个问题?

【问题讨论】:

  • 是否有许多用户可以访问的 m3u8 的小列表?一种选择可能是异步生成一个新的 m3u8,然后在接下来的几个小时内提供它,然后再生成一个新的。如果有数百万个不同的 m3u8,这可能行不通。
  • @BrandonYarbrough;截至目前,该网站共有 678 个视频(相当于 4,068 个 m3u8 [180,360,480,720,1080,AAC 各一个])。尽管您提出了一个好主意...我可以编写一个脚本,每 x 小时生成一次所有 m3u8,将其发布到 dB 并在为播放器生成 uris 时从那里提取...一个可行的解决方案...我去玩一下,看看我得到了什么。

标签: php google-cloud-storage


【解决方案1】:

经过更多研究,我得出以下结论:

我的第一次计算是使用 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 文件,因此不必在客户端进行黑客攻击。

希望这可以帮助有类似问题的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-22
    • 1970-01-01
    • 2019-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 2014-01-12
    相关资源
    最近更新 更多