前置知识: 运维与中间件

云存储基础与 CDN

11 min入门

接着「三台服务器裸奔上云」讲数据的归宿:块存储挂盘、对象存储放文件、文件存储做共享目录的三类选型,快照与生命周期策略,以及 CDN 的回源与缓存失效机制。

知识点地图

  • 知识类别:云存储三类型(块存储/对象存储/文件存储)与 CDN 内容分发——数据上云的「存」与「取」两个基本面。
  • 解决什么问题:应用上线后数据放哪里(数据库磁盘、用户上传、共享配置、静态资源各属谁管)、怎么备份到「回得到昨天」、怎么让全球用户取静态资源不慢。
  • 什么时候用到:给三台服务器配数据盘之后;第一个用户上传功能上线之前;静态站点要提速时。存储与网络是同一张拓扑的两半——VPC/安全组/NAT 见云网络基础;托管数据库/对象存储的完整服务族见云存储服务。

0. 场景衔接:三台服务器稳住了,数据往哪放

云网络基础里那三台裸奔的服务器,划好 VPC、收口安全组之后活过了一周。紧接着第二类问题浮出水面:

  • 数据库那台机器,磁盘满了怎么办?盘坏了数据怎么回到昨天?
  • 用户开始上传头像和报表文件,全部塞应用服务器的本地盘显然撑不住;
  • 团队三个人都在往各自的机器上放同一份配置文件,版本已经对不上了;
  • 首页的图片和脚本让用户抱怨「打开太慢」,可服务器明明很空闲。

四个问题对应四个答案:块存储管磁盘与快照,对象存储管海量文件与备份,文件存储管共享目录,CDN管静态内容就近分发。本文按这条线展开,命令仍以 AWS 为例,概念在任何云上一一对应。

1. 块存储:数据库的磁盘

块存储(AWS 叫 EBS)像一块可以插拔的硬盘,挂给虚拟机当磁盘用。 三种主流盘型的取舍:

盘型特点适用
通用 SSD (gp3)基线 3000 IOPS,可独立加购系统盘、一般应用,默认选它
高性能 SSD (io2)IOPS 上不封顶高负载数据库
HDD (st1)便宜、吞吐型日志、冷数据

数据库最怕的不是丢,是回不到昨天。快照(snapshot)解决它: 增量备份、存进对象存储、可随时恢复成新盘。手动打快照靠人记性, 生产用 DLM(Data Lifecycle Manager)声明策略,机器执行:

bash
aws dlm create-lifecycle-policy \
  --execution-role-arn arn:aws:iam::xxx:role/DLMRole \
  --description "Daily EBS backup" --state ENABLED \
  --policy-details '{
    "PolicyType": "EBS_SNAPSHOT_MANAGEMENT",
    "ResourceTypes": ["VOLUME"],
    "TargetTags": [{"Key": "Backup", "Value": "daily"}],
    "Schedules": [{
      "Name": "DailyBackup",
      "CreateRule": {"Interval": 24, "IntervalUnit": "HOURS", "Times": ["03:00"]},
      "RetainRule": {"Count": 7},
      "CopyTags": true
    }]
  }'

读这段策略的方式和读 YAML 声明一样,逐层拆:

  • TargetTags 是筛选条件——策略只作用于带 Backup=daily 标签的卷,这是声明式自动化惯用的「打标锚点」;
  • CreateRule 定义节奏:每天 03:00(业务低谷)打一次;
  • RetainRule 定义保留:只留最近 7 份,成本封顶;
  • CopyTags: true 让快照继承卷的标签,方便后续按标签审计与清理。

一句话总结:每天 03:00 给所有带 Backup=daily 标签的卷打快照,保留最近 7 份。标签是这套自动化的锚点——忘记给数据卷打标签,策略就永远不会覆盖它。

三个场景体会「块存储管什么」:数据库的数据目录(必须低延迟、随实例启停可挂拔);工程场景里容器集群的持久卷(块盘是多数云上 StatefulSet 的默认底座);个人开发机的系统盘扩容(gp3 加容量不重启)。共同点:需要「像本地磁盘一样挂载」的场景。

2. 对象存储:文件、备份与静态站点

对象存储(AWS 叫 S3)没有”目录和磁盘”的概念,就是一个巨大的 键值空间:每个对象一个 key、一份内容、若干元数据,通过 HTTP API 读写。三个决定性特征:容量无上限、按用量计费、数据持久性设计值 高达 99.999999999%(11 个 9,靠多副本/多设施实现)。

常用操作两条命令就够(更多见《AWS S3 命令》):

bash
aws s3 cp report.pdf s3://my-app-bucket/documents/report.pdf
aws s3 presign s3://my-app-bucket/documents/report.pdf --expires-in 3600
# presign 生成 1 小时有效的临时下载链接——客户端直传/直下都靠它
  • 第一条把本地文件放进桶;key 是 documents/report.pdf,斜杠只是 key 里的字符,「目录」是给人看的假象;
  • 第二条是对象存储最有工程价值的一招:服务器生成带签名的临时 URL,浏览器拿它直接对 S3 下载——大文件流量不再过你的应用服务器。换成传统写法(应用读文件再回给用户)会发生什么:应用服务器带宽被打满、实例数被迫随下载量扩容;presign 把「传输」下放给对象存储,「授权」留在自己手里。

对象存储的省钱开关是生命周期分层:访问频率随时间下降的数据 (日志、备份、旧附件)自动在存储层级间搬家:

json
{
  "Rules": [{
    "ID": "ArchiveOldLogs",
    "Status": "Enabled",
    "Filter": { "Prefix": "logs/" },
    "Transitions": [
      { "Days": 30,  "StorageClass": "STANDARD_IA" },
      { "Days": 90,  "StorageClass": "GLACIER" }
    ],
    "Expiration": { "Days": 365 }
  }]
}

逐段读语义:Filter 限定只作用于 logs/ 前缀的对象;Transitions 是迁移阶梯——30 天后转低频层(取回稍慢、单价更低)、90 天后转归档层(取回要「解冻」、单价最低);Expiration 是终点——365 天直接删除。三个场景体会对象存储的适用面:用户上传的图片附件(presign 直传直下);数据库日志与快照的长期归档(生命周期自动分层);静态网站托管(整桶当网站发布,配合下一节 CDN)。

3. 文件存储:给团队一个共享目录

块存储一次只能挂给一台机器,对象存储没有「目录树」语义——当一群机器要同时读写同一份文件集时,两者都不合适,这轮到文件存储(AWS 叫 EFS,Azure 叫 Azure Files,GCP 叫 Filestore)。它把一个 POSIX 语义的共享目录以 NFS 协议暴露出来,成百上千台机器可以同时挂载,容量随写入自动增长。

什么场景会需要它:

  1. 共享配置与模型文件:多台应用服务器挂同一个目录放配置、词表、AI 模型权重,改一处全生效——比「每台机器自己拉取再同步」少一整套同步逻辑;
  2. 工程场景:容器集群的共享持久卷:K8s 里多个 Pod 共享读写同一份文件(日志汇总、批处理工作目录),文件存储是最直接的挂载选项;
  3. 开发与内容团队:几十人的共享工作区,权限按目录管理,替代自建 NAS。

三类存储的本质差异一句话说透:块存储卖的是「一块盘」(实例级、低延迟、按容量与 IOPS 计费),文件存储卖的是「一个目录树」(多机共享、POSIX 语义、按容量计费),对象存储卖的是「一个键值空间」(无限扩展、HTTP 访问、按请求与流量计费)。

4. 三类存储选型对比

维度块存储文件存储对象存储
形态挂载的磁盘共享目录树HTTP 键值空间
访问协议块设备(随文件系统)NFS/SMBREST/HTTP
并发挂载通常单机成百台机器无限(按请求)
延迟最低(毫秒内)低到中中(每请求 HTTP 往返)
计费锚点容量 + IOPS容量 + 吞吐容量 + 请求次数 + 出流量
典型用途数据库、系统盘共享配置、容器共享卷上传文件、备份、静态站

决策顺序也照这个表从左往右问:需要「当磁盘用」吗?需要「多机共享同一目录」吗?都不是——那就是对象存储。选型拿不准时优先对象存储:它的访问模型最松耦合,未来迁移成本最低。

5. CDN:把静态内容搬到用户门口

对象存储解决”存得下”,CDN 解决”取得快”:内容复制到全球边缘节点, 用户就近取,没命中才回源站。缓存规则的经验值:

资源缓存时间原因
图片/CSS/JS天级到月级内容不变,改版靠文件名带哈希
HTML 页面分钟级更新频繁,太长会缓存住旧页面
API 响应不缓存动态数据,除非明确可缓存

5.1 回源与缓存失效:CDN 的两个关键机制

上面这张表能成立,靠的是两套机制配合,理解它们才算懂 CDN:

回源(origin fetch)的完整流程:用户请求边缘节点 -> 节点查缓存(按 cache key 命中判断)-> 命中则直接返回;未命中则节点向源站(你的 S3 桶或应用服务器)取一份,存入缓存后再回给用户。缓存键通常由「域名 + 路径 + 查询参数」组成——这也是为什么同一个 URL 在不同节点会各自缓存一份。

**缓存失效(invalidation)**决定「改了内容,用户多久能看到新版本」。两条路线:

  1. 文件名带内容哈希(首选):app.a3f9c2.js 改版后变成 app.b7e1d0.js,URL 变了就是新缓存键,旧缓存自然过期,无需任何主动失效。构建工具(Vite/webpack)产出的哈希文件名就是为这件事设计的;
  2. 主动失效(invalidation,补刀用):控制台或 API 通知边缘节点丢弃某些路径的缓存(AWS 叫 create-invalidation)。它是即时生效但按次数计费的操作,适合 HTML 这类不宜改名的入口文件。如果把每张图片的更新都靠主动失效来解决,费用和延迟都难看——那说明该用路线 1。

配套的服务器响应头也要认识:Cache-Control: max-age=31536000, immutable 告诉 CDN 与浏览器「这个文件一年内不用再问」;HTML 则给 max-age=60 这类短值。CDN 尊重源站的这些头,除非你在分发配置里覆盖了 TTL。

判断优化是否有效的第一个指标是缓存命中率。FANDEX 这类静态文档站 整站构建产物都是不可变文件,天然适合”对象存储 + CDN”的零服务器组合。 实操见《AWS CloudFront》。

6. 坑点与自检

  1. 对象存储分层的”最短存储时间”陷阱。低频层 30 天、归档层 90 天 起存,提前删除照收费;频繁回迁的”冷”数据走归档反而更贵——先看 访问模式再分层。
  2. 快照策略没绑对标签。新建的数据卷忘了打 Backup=daily, DLM 永远不备份它。定期审计”有卷无标签”的资源。
  3. CDN 改版后用户看到旧页面。图片等哈希文件名资源靠 URL 变化自动 换新;HTML 入口文件是唯一该走主动失效的对象,且 TTL 要配短。
  4. 把文件存储当无限网盘。文件存储按容量持续计费,几十 GB 的 “丢进去就忘”的备份放对象存储便宜一个数量级。

自检清单:

  • 能对着表说出三类存储各自「卖的是什么」
  • 数据卷打了备份标签且 DLM 策略在运行
  • 静态资源用哈希文件名,HTML 走短 TTL,主动失效只留给入口文件
  • 能说出一次 CDN 请求未命中时的完整回源流程

7. 练习与动手实践

练习:

  1. 给第 1 节的数据盘打上标签并创建 DLM 策略,次日检查快照是否生成。
  2. 建一个 S3 桶,上传几个文件后配置第 2 节的生命周期规则,在 控制台里核对规则是否生效。
  3. 用 presign 生成一条下载链接,分别在链接有效期内与过期后访问, 观察行为差异。

动手实践任务:为你的一个静态项目(哪怕是单页简历)设计完整的 「对象存储 + CDN」发布方案并写下来:桶结构、Cache-Control 策略、 改版发布流程(含要不要主动失效)。写完对照参考实现。

提示:

  • 先分清单里哪些文件内容不可变(哈希命名),哪些会变(HTML/JSON 入口);
  • 改版流程要回答「新版本上线那一刻,老缓存怎么办」;
  • 想一想命中率与成本的关系:命中率提升 10%,回源流量降多少。

参考实现(先自己写,再对照):

text
发布方案(示例):

桶结构:
  assets/    ——— js/css/图片,构建产物文件名自带内容哈希
  index.html ——— 入口,内容常变

Cache-Control:
  assets/*:max-age=31536000, immutable(一年,内容不可变)
  index.html:max-age=60(一分钟,改动快速生效)

发布流程:
  1. 构建产出新哈希文件名的 assets,上传(只增不改,旧文件保留
     一个版本周期,照顾还在用旧页面的用户)
  2. 上传新的 index.html
  3. 仅对 index.html 发起一次 create-invalidation
  —— 主动失效只出现在第 3 步,一个月通常个位数次

成本自检:命中率高于 95% 才算健康;低于它先查有没有把 HTML 也
配成了长缓存。

对照要点:方案的核心判断只有一个——把「内容会变」压缩到最少量的 URL 上,其余全部走不可变 + 长缓存。凡是发布方案里主动失效一大串 路径的,都是哈希命名没做彻底。

参考与致谢