3.1 存储桶规划:地域、命名与访问权限

社区上线第二个月的一个早上,一条云监控告警把我吵醒:数据盘利用率超过 85%。我爬起来看了一眼,新增的几乎全是用户上传的图片,一天能涨好几个 GB。我坐在电脑前算了笔账:云硬盘按容量包月收费,为了存图片每隔几个月就要扩容一次,每个月固定多出一笔钱;而这笔钱大半花在没什么人看的旧图上,后台数据显示,上月上传的图片有七成在 30 天后就几乎没什么访问了。更要命的是备份,我得自己写定时脚本打包图片,还得愁打包出来的压缩包往哪放。

那几天我做了一个决定:把图片整体迁到对象存储 COS。动手之前我先花了半天做规划,事实证明这是对的——地域、名字、权限一旦定错,后面改起来比写代码还疼。本篇就讲规划期必须想清楚的几件事。规划没做扎实就动手建桶,是很多人上云第一笔冤枉钱的来源。

为什么图片适合放对象存储

对象存储和我熟悉的文件系统是两套完全不同的思路。它没有目录树,文件在这里叫对象(Object),装在存储桶(Bucket)里,全部通过 HTTP 接口读写。它有几个特性正好撞上图片社区的诉求:

特性 对图片社区的意义
容量弹性 不用再盯磁盘利用率,传多少存多少,没有扩容操作
按量计费 只为实际占用的容量和请求次数付费,冷数据还能更便宜
HTTP 原生访问 每张图天然就是一个 URL,后面接 CDN 加顺理成章
服务端多副本 数据冗余由服务端保证,备份这件事不用我再操心

在决定上云存储之前,我也认真考虑过自建一套家庭服务器放图片,具体怎么选可以看我另一本NAS 与家庭服务器实战,那里对家用硬盘方案和成本做过完整对比。结论是:对线上项目来说,对象存储省心得多,我不用担心哪块硬盘突然坏掉带走一批用户图,也不用半夜爬起来换盘。

如果你和我一样是第一次接触对象存储,有个概念先记住:对象的访问域名长成 存储桶名.cos.地域.myqcloud.com 这个样子,地域这段就是下一节的主角。

地域:和 CVM 同区是省钱的起点

存储桶的地域(Region)不能凭感觉选。我的原则只有一条,简单粗暴:和 CVM 同一个地域。

同地域之后,服务器访问 COS 走的是内网链路。这有两个直接好处:一是延迟低,同一地域的机房链路质量稳定;二是内网流量不计费。我最初不懂,随手把存储桶建在了和 CVM 不同的地域,后端每读一张图都走公网,月底账单里多出一笔外网下行流量费。金额不算大,但完全是白花的钱,把存储桶改建成同地域之后,这笔费用当月就消失了。

判断地域其实不用敲命令。控制台的存储桶列表里,每个桶后面都标着地域;再去 CVM 实例列表里对着看一下,两边一致就行。顺带一提,我的云数据库 MySQL 也选了同地域,CVM 内网访问 MySQL 走的是同一套逻辑,这在第二篇已经聊过。

如果你想验证服务器到 COS 是不是真走了内网,最直观的办法是抓包看请求走的是内网 IP 还是公网 IP,控制台的地域标签则帮你确认配置没写错。另外还有个选地域的现实因素:主要用户集中在哪个区域。不过这个因素在第四篇接上 CDN 之后会被大幅削弱——用户访问的是 CDN 边缘节点,不用直连源站。所以对存储桶来说,和服务器同区永远是第一优先级,面向用户的速度交给 CDN 来解决。

多啰嗦一句:地域选好后,上传代码里写的 Endpoint 或者 SDK 配置里的 Region 一定要和它对上。我第一版 SDK 配置里把地域拼错了,上传一直超时,查了半小时才反应过来是链路根本不通。另外存储桶的地域在创建之后不可更改,这一点务必在点下创建按钮前确认清楚。

命名:全域唯一这个小坑

创建存储桶时我栽过一个小跟头,估计每个新手都会遇到:我想把桶命名为 my-community-images,系统直接报错说名字已被占用。存储桶名称是所有用户共享的命名空间,全域唯一,和域名一样先到先得,重名就创建失败。

命名规则也挺严格:只能用小写字母、数字和短横杠,长度有上下限,而且不能以横杠开头或结尾。我最后用了 pic-community-1250000000 这种形式,前面是可读的项目名,后面接上账号的 AppID 后缀。这样既绕开了重名问题,一眼看过去也知道是谁家的桶。

这里有两个经验:第一,创建前先想好名字,存储桶没法改名,填错了只能重建;第二,如果你和我一样手头有好几个环境,建议直接在名字里区分开,比如开发环境叫 dev 前缀,别等地域和权限都配好了再想搬家,搬家要重新传一遍全部对象。

顺带记一笔小账:测试桶建好之后往往随手用了好几个月,里面堆了一堆调试图片。定期清理这些桶,或者干脆给测试桶也配上生命周期规则自动清理,是个便宜又省心的习惯。日常本地素材越积越多的时候,分类整理的方法可以参考笔记知识库整理指南,思路和云端存储规划其实相通。

访问权限:私有读是底线

存储桶权限的坑最深,我在边上站了挺久才想明白。三种权限先放在一张表里:

权限类型 读取 写入 我的评估
私有读写 需要签名验证 需要签名验证 生产环境默认,最安全
公有读私有写 任何人可直接访问 需要签名验证 图床常用,但要防外部刷量
公有读写 任何人可读写 任何人可读写 连测试都尽量别开

我的选择是私有读写打底。你可能要问:图片不给看,社区怎么办?答案是私有桶并不意味着不能公开访问,而是把怎么访问的控制权拿在自己手里——要么由后端生成带签名的临时 URL 下发给前端,要么走 CDN 回源鉴权(这部分在第四篇细聊)。签名 URL 有有效期,过期了就打不开,这个机制比裸 URL 安全太多。它的原理不复杂:后端拿永久密钥对请求参数签名,浏览器拿到的是一把限时钥匙,形式上就是附加在 URL 后面的一串签名参数。

公有读看着方便,但代价是图片 URL 泄露之后谁都能无限刷,流量费直接算在我头上。这件事我后来真的经历了一次,写在 3.3 篇里。另外测试的时候为了方便,可以短暂开一下公有读,用完千万记得关回去,顺手给自己设个日历提醒也行。

再补一点:桶级权限是默认值,单个对象还能单独设置权限。比如某张图要临时分享给运营核对,用对象级权限或签名 URL 都行,不必动整个桶。

COS 的费用由三块组成

选型阶段搞清楚账单结构,比上来就比价更有用。COS 的费用大致分三部分:

  • 存储费:按容量和存储类型计费,一般是大头。存储类型有标准、低频、归档几档,冷数据便宜很多。
  • 请求费:按调用次数计费,单次便宜,但量大了也看得到。
  • 流量费:外网下行流量和 CDN 回源流量要计费,内网流量不要钱。

请注意最后一条和地域的选择是联动的:同地域走内网,存储费该多少还是多少,但流量费直接免了。这三项费用具体花了多少,我在 5.4 成本复盘里摊开算过。规划阶段只要记住一条原则:把热数据和冷数据分开存放,是后面所有省钱操作的前提,具体怎么分在 3.4 篇展开。

费用预估有个偷懒的办法:腾讯云官网提供价格计算器,把预计的存储容量、月请求数和流量填进去就能估出月账单。我在正式迁移前用它跑了两版方案对比,发现旧图占大头的情况下,拉开存储类型档位的收益远比抠请求费大——这个判断直接决定了 3.4 篇的做法。规划期多算十分钟,上线后少心疼一年。

如果你正在凑齐第一套云资源,云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中是新用户入手的好入口,我第一年的云资源就是从这里下手的,比列表价便宜不少。新用户身份只能用一次,所以最好等账号名下资源规划清楚了再下手。

规划定稿,下一节我们正式开始传图。最后给一张创建存储桶前的自检清单,照着过一遍能少走不少弯路:

  • 地域和 CVM 是否一致(内网访问的前提)
  • 桶名是否符合规则且未被占用(创建前先在控制台试一次)
  • 权限默认选私有读写,公有读要有明确的理由
  • 记下访问域名和 Endpoint,后端代码里要用
  • 想好对象的 Key 层级结构,这决定以后生命周期规则怎么配

延伸阅读