如何实现请问 A 服务器当文件不存在时向 B 下载,并在下一次请求时使用本地文件

2019-07-17 18:11:34 +08:00
 Liang
背景是这样的:
公司业务的文件存储是用 OSS 的,奈何 OSS 一时爽,后面的流量费用准备回家找房产证了。

公司最近托管了一台服务器 A,流量不限,打算暂时用 A 做“ CDN ”,只在 A 本地不存在请求文件的时候,去 OSS 拿,拿完后存在本地,下次再请求时,直接使用即可。

这样考虑是为了不影响现有的文件上传业务,也不需要一下次把所有的 OSS 文件拉取回来,托管的服务器如果也可以随时下掉。

当然如果有更优的方案就更好了,目前想解决标题的问题,貌似 nginx 的 proxy_cache 可以做,但是是缓存,不是文件的真实地址,求各位大神指路。
2243 次点击
所在节点    程序员
20 条回复
37Y37
2019-07-17 18:39:37 +08:00
try_file  试试这个模块
cjpjxjx
2019-07-17 18:51:31 +08:00
我也在考虑一个类似的问题,在家里的服务器上搭建网站,有公网 IP,带宽大还不限流量,但是家里的服务器不可能有云服务那么稳定,想实现当家里停电或断网时,自动切换到云服务器顶上,而且数据是保持同步的
Liang
2019-07-17 18:59:57 +08:00
@cjpjxjx 我倒没想自动切。文件服务器的域名是配置的,可以随时改,这段时间用 A,如果 A 要用于正式业务再改个域名切回 B 就行了。目前而言不至于把 B 所有的文件都下回 A,流量费用又是一大笔
chinvo
2019-07-17 19:28:09 +08:00
try_files 最后写个 rewrite,302 到另一个 url
wewall
2019-07-17 19:29:00 +08:00
php 是世界上最好的语言
wewall
2019-07-17 19:29:43 +08:00
@chinvo 这样并没有达到缓存一份到本地的需求啊
liang96
2019-07-17 19:36:54 +08:00
@cjpjxjx 家里的网络都没开 80 和 443 吧
runtu2019
2019-07-17 19:45:14 +08:00
https://www.fikker.com/

有个硬盘缓存的功能,可以将文件缓存在内存和硬盘中,应该可以满足你的需求
chinvo
2019-07-17 19:46:44 +08:00
@wewall 那就做个 proxy_pass,然后 proxy_cache
MonoLogueChi
2019-07-17 19:52:05 +08:00
自己写个程序,404 的时候 302 跳过去,然后后台下载回来?第一想法是这样
Edward4074
2019-07-17 20:02:55 +08:00
如果服务器也是阿里的话,oss 走内网是免流量费的
runtu2019
2019-07-17 20:10:55 +08:00
Apache Traffic Server
忽然想到这个这个也是可以做持久化缓存的!
gamexg
2019-07-17 20:35:20 +08:00
服务器 A 404 时重定向到 oss。
然后定期拉去 nginx 日志,找到 302 的条目下载。
KasuganoSoras
2019-07-17 20:42:20 +08:00
<?php
$api = "https://example.com/";
$file = __DIR__ . "/cache/" . md5($_GET['file']);
$real = realpath($file);
if($real == "" || !file_exists($real)) {
$data = file_get_contents("{$api}{$_GET['file']}");
if(strlen($data) > 0) {
@file_put_contents($file, $data);
} else {
exit("Cannot fetch data!");
}
}
$real = realpath($file);
$fi = new finfo(FILEINFO_MIME_TYPE);
$mime = $fi->file($real);
$file_name = basename($real);
Header("Content-Type: {$mime}");
Header("Content-Length: " . filesize($real));
Header("Content-Disposition: attachment; filename={$file_name}");
readfile($real);
exit;

随手写的,不知道能用不(
laozhoubuluo
2019-07-18 00:05:14 +08:00
但是是缓存,不是文件的真实地址?? 这句没看懂。

1.图省事的做法就是 OSS 配好缓存时间,完了 nginx 的 proxy_cache 或者 squid 解决。
好处就是缓存什么文件 nginx 代劳了,不用考虑什么是热点内容。
缺点就是所有流量经过 A,浪费双份流量,并且 A 断了会引起业务中断。当然如果有逐步下掉 OSS 的计划,这样做最好不过。

2. 要么就是 nginx 的 try_files+302 解决。
好处就是客户端配置一个域名可以搞定,并且不会浪费流量。
缺点就是 A 断了会引起业务中断,并且需要定期分析日志决定什么内容放在 A 上,否则可能不优化。

3. 如果能接受客户端发版,可以考虑改造 HTTP 请求相关代码,第一次请求走 ServerA,如果返回代码!=200 或者请求失败,第二次请求走 OSS。
优点是这样比较强健,ServerA 断了不影响业务,并且不会浪费流量。
缺点就是要改造客户端代码,另外也需要定期分析日志决定什么内容放在 A 上,否则可能不优化。
laozhoubuluo
2019-07-18 00:08:27 +08:00
我重新看了一下需求,您希望 ServerA 100%缓存流经的内容的话,就用 proxy_cache 吧,完了 OSS 侧给个巨大的缓存头解决问题。
goodryb
2019-07-18 00:31:40 +08:00
贵司不会是直接提供 oss 来直接下载文件吧,oss 是做存储的,如果是下载类的,前面必须要套个 CDN,这样就算回源到 OSS,访问的流量也会非常少。

如果觉得回源流量还是太大,可以考虑用你中间这台服务器做个二级缓存。CDN 一般都会有源站检测功能,把你的服务器和 oss 都配置成源站,优先走你的服务器,服务器要是挂了,自动走 oss 回源。
ryd994
2019-07-18 06:17:41 +08:00
如果是想缓存,但是上游内容可能变,proxy_cache
如果是想镜像,上游内容不变,proxy_store + try_files
官方文档里就有例子,我个人建议第二种用 @ named location 的
ryd994
2019-07-18 06:18:51 +08:00
Liang
2019-07-18 15:21:38 +08:00
@laozhoubuluo 比如我是 picture/123.jpg ,proxy_cache 在本地不会写入 picture/123.jpg ,而是 cache/01,cache/02

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/583891

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX