1_AWS核心服务实战技巧
1. 基础:Region / AZ / VPC
在 AWS 上跑应用,先把三个名词分清:Region(区域)、AZ(Availability Zone,可用区)、VPC(Virtual Private Cloud,虚拟私有云)。这三个词决定了你的资源在地球上的哪里、容灾级别多高、网络隔离边界划在哪。
环境准备:本文示例统一基准 Region 为
us-west-2(俄勒冈),CLI 命令均带--region us-west-2。如果你刚开通账户,请先在 IAM 里建一个有 EC2/VPC 只读权限的子账户用于练习,避免直接用 root。
1.1 概念三件套:Region / AZ / VPC
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6', 'primaryTextColor': '#1E3A5F', 'primaryBorderColor': '#2563EB', 'lineColor': '#60A5FA'}}}%%
flowchart TD
subgraph Region ["Region(区域)"]
direction TB
subgraph AZ1 ["可用区 A"]
DC1["数据中心 1"]
DC2["数据中心 2"]
end
subgraph AZ2 ["可用区 B"]
DC3["数据中心 3"]
DC4["数据中心 4"]
end
subgraph AZ3 ["可用区 C"]
DC5["数据中心 5"]
end
end
AZ1 <--> |"低延迟 ≤2ms"| AZ2
AZ2 <--> |"低延迟 ≤2ms"| AZ3
classDef region fill:#DBEAFE,stroke:#2563EB,color:#1E3A5F
classDef az fill:#D1FAE5,stroke:#059669,color:#065F46
classDef dc fill:#FEF3C7,stroke:#D97706,color:#92400E
class Region region
class AZ1,AZ2,AZ3 az
class DC1,DC2,DC3,DC4,DC5 dc| 概念 | 定义 | 类比 |
|---|---|---|
| Region(区域) | AWS 在全球的物理地理区域(如 us-east-1、ap-northeast-1) | 城市 |
| AZ(Availability Zone,可用区) | Region 内物理隔离的数据中心集群,独立电力/冷却/网络 | 城市内的独立园区 |
| VPC(Virtual Private Cloud,虚拟私有云) | Region 内逻辑隔离的私有网络,由你掌控 IP/子网/路由 | 园区里你租下的那栋楼 |
一个 Region 通常含 3 个或以上 AZ;同 Region 内 AZ 之间走 AWS 自己的高带宽光纤,往返延迟一般 1-2 ms。VPC 是 Region 级资源——一个 VPC 不能跨 Region,但可以跨 AZ(其子网分别落在不同 AZ)。
1.2 Region 选择策略
入门最常见的纠结是「我该把服务部署在哪个 Region」。按下面四个维度排顺序基本不会错:
| 维度 | 决策建议 |
|---|---|
| 延迟 | 选离用户最近的 Region。中国大陆访问国外服务器,东京 ap-northeast-1 / 新加坡 ap-southeast-1 通常优于美西 |
| 合规 | 涉及个人数据要符合当地法规(欧盟 GDPR、中国《个人信息保护法》、美国 HIPAA 等)时,必须选数据落地在合规辖区的 Region |
| 灾备 | 关键业务建议主备分别部署在两个 Region。主区与备区距离不要太近(如 us-east-1 + us-west-2 而非 us-east-1 + us-east-2) |
| 成本 | 同样的 EC2 机型在不同 Region 价格能差 10–30%。us-east-1(弗吉尼亚)通常最便宜,ap-northeast-1(东京)通常最贵 |
实操原则:先满足合规与延迟,再在剩余候选里挑成本最低的。
1.3 多可用区架构与成本
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart TB
subgraph VPC ["VPC: my-vpc (10.0.0.0/16)"]
subgraph AZA ["us-east-1a"]
PubA["public-subnet-a 10.0.1.0/24"]
PriA["private-subnet-a 10.0.2.0/24"]
end
subgraph AZB ["us-east-1b"]
PubB["public-subnet-b 10.0.3.0/24"]
PriB["private-subnet-b 10.0.4.0/24"]
end
end
PubA --> |"ELB, NAT GW"| PriA
PubB --> |"ELB 节点"| PriB
PriA --> |"EC2, RDS主"| PriB
PriB --> |"EC2, RDS备"| PriA
classDef pub fill:#DBEAFE,stroke:#2563EB
classDef pri fill:#FEE2E2,stroke:#DC2626
class PubA,PubB pub
class PriA,PriB pri💰 跨 AZ 流量:us-west-2 内同 Region 跨 AZ 流量 $0.01/GB——发送方和接收方各按出方向计一次费,所以一次 1 GB 的跨 AZ 调用,账单上是 $0.02。
来源:AWS EC2 Pricing API JSON (us-west-2)
AZ 间延迟 1–2 ms,对绝大多数应用可忽略。核心结论:跨 AZ 部署是性价比最高的高可用方案,单 AZ 故障不会拖垮服务。但要警惕大流量服务的跨 AZ 账单:EC2 ↔ RDS 主备频繁同步、应用层与缓存层不在同一 AZ,月底账单可能比想象的多一截。
1.4 VPC 子网三分法
把 VPC 内的子网按互联网可达性分成三类,是几乎所有生产架构的默认起手式:
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart LR
Internet((Internet))
subgraph VPC ["VPC 10.0.0.0/16"]
direction TB
subgraph Pub ["公有子网 Public"]
ALB["ALB / NAT GW / 堡垒机"]
end
subgraph Pri ["私有子网 Private"]
APP["EC2 / ECS 应用层"]
end
subgraph Iso ["隔离子网 Isolated"]
DB["RDS / ElastiCache 数据层"]
end
end
Internet <--> |"IGW"| Pub
Pub --> |"NAT GW"| Pri
Pri --> Iso
classDef pub fill:#DBEAFE,stroke:#2563EB,color:#1E3A5F
classDef pri fill:#FEF3C7,stroke:#D97706,color:#92400E
classDef iso fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D
class Pub,ALB pub
class Pri,APP pri
class Iso,DB iso- 公有子网(Public Subnet):路由表含
0.0.0.0/0 → IGW,子网内资源可双向访问公网。放对外暴露的组件:ALB(应用负载均衡器)、NAT Gateway、堡垒机。 - 私有子网(Private Subnet):路由表含
0.0.0.0/0 → NAT GW,能访问公网(拉镜像、调外部 API),但公网无法主动连入。放业务应用层:EC2、ECS、Lambda 的 VPC ENI。 - 隔离子网(Isolated Subnet):路由表无
0.0.0.0/0默认路由,与公网完全断开。放数据层:RDS、ElastiCache、自建数据库。
为什么要这么分?两件事:最小爆破半径与安全分层。万一应用层被攻陷,攻击者也无法从私有子网直接 SSH 出去外联 C2 服务器(无入站路径);万一应用层 SSRF 漏洞被利用,隔离子网的数据库也连不上外网,无法把数据偷偷传出去。每多一层路由隔离,就多一道兜底防线。三分法是把网络风险降到合理水平的最小代价。
1.5 路由表与互联网网关
理清两个组件的关系就够了:
- IGW(Internet Gateway,互联网网关):VPC 边界的「互联网门」,挂在 VPC 上,本身没有带宽限制也不收费
- 路由表(Route Table):每个子网必须关联一个路由表;表里有
0.0.0.0/0 → igw-xxx的子网就是公有子网
最小路由表示例(YAML 风格伪码,仅示意字段结构,非 CloudFormation/Terraform):
1 | # 公有子网路由表 |
判断一个子网是公有还是私有,只看它关联的路由表里 0.0.0.0/0 指向哪里,不看子网的名字。
1.6 Security Group Vs Network ACL
VPC 里有两层防火墙:
- Security Group(SG,安全组):作用在实例网卡(ENI)
- Network ACL(NACL,网络访问控制列表):作用在子网
新手最容易混淆两者,下面这张决策表:
| 维度 | Security Group | Network ACL |
|---|---|---|
| 作用层级 | 实例(ENI) | 子网 |
| 状态 | 有状态(自动放回程) | 无状态(出入站都要规则) |
| 规则类型 | 仅 allow | allow + deny |
| 默认入站 | 全拒绝 | 默认 NACL 全允许;自建 NACL 全拒绝 |
| 评估顺序 | 全部规则求并集 | 按规则号从小到大,命中即返回 |
| 可引用对象 | SG / CIDR | 仅 CIDR |
| 典型用途 | 应用层细粒度访问控制 | 子网级粗粒度黑名单 |
实操上,新手 90% 时候只用 SG 就够。SG 之间可以互相引用(如 ALB-SG 作为 EC2-SG 的 source),表达力强,且有状态省心。NACL 通常用于两种场景:阻挡某段恶意 IP(用 deny 规则)、合规要求子网级强制隔离。除此之外可以保持默认 NACL 全开。
1.7 查看 EC2 所在区域
EC2 是 Region 级资源,控制台必须切到对应 Region 才能看到实例——很多新手「实例消失了」的疑问,95% 是 Region 切错。AZ(如 us-west-2a)在 EC2 实例列表「可用区」一列直接展示。CLI 查询一行:
1 | # 列出 us-west-2 下所有运行中实例的 ID、AZ、私网 IP |
💡 进阶 / IAM:可以用 IAM Condition 限制某个角色只能在指定 VPC 内创建 EC2 实例,避免误操作把资源开到别的网络里。示例:
1
2
3
4
5 "Condition": {
"StringEquals": {
"ec2:Vpc": "arn:aws:ec2:us-west-2:<account-id>:vpc/<vpc-id>"
}
}把这段挂到
ec2:RunInstances的 IAM 策略上,调用方若没指定该 VPC 就会被拒绝。生产账户里给开发人员做权限隔离时很常用。
1.8 常见踩坑
- 私有子网实例
apt update/yum update卡死- 现象:从堡垒机 SSH 进私有子网的 EC2,跑
apt update一直 hang,超时退出 - 根因:私有子网的路由表里没有
0.0.0.0/0 → NAT GW这条出口;或路由有但 NAT Gateway 还没建,或建在了别的 AZ 不在同一路由域 - 处理:检查私有子网关联的路由表,确认默认路由指向 NAT GW;NAT GW 自身必须放在公有子网(它要走 IGW 出网)。NAT GW 与私有子网不强制同 AZ,但生产环境建议每 AZ 各部署一个独立 NAT GW,避免跨 AZ 流量费 + 单 AZ 故障影响
- 现象:从堡垒机 SSH 进私有子网的 EC2,跑
- 跨 AZ 部署后流量账单暴涨
- 现象:上线多 AZ 架构后第一个月账单里
Regional Data Transfer一项比预期高几倍 - 根因:应用层与数据层、缓存层未就近部署在同 AZ;或 RDS Multi-AZ 主备频繁切换;或 ALB 的 Cross-Zone Load Balancing 把流量均匀打到所有 AZ 的后端,引起大量 ALB → EC2 的跨 AZ 流量
- 处理:让应用 EC2 与对应 RDS 主实例尽量同 AZ;评估关闭 ALB Cross-Zone Load Balancing 或接受其代价;对内部高频通信链路(如应用 → 缓存)按 AZ 局部性部署
- 现象:上线多 AZ 架构后第一个月账单里
- SG 修改后旧 TCP 连接还在通
- 现象:把某 IP 从 EC2-SG 入站规则里删掉,但已经登录的 SSH 会话仍然没断
- 根因:SG 是有状态的,已建立连接(established)不受新规则影响,新规则只对后续新建连接生效
- 处理:要立刻切断已有连接,需在实例端
kill掉对应进程或重启 sshd;或在 NACL 加一条 deny 规则强制切断(NACL 无状态,对存量连接也生效)
VPC、子网、SG 是房子的骨架。骨架立好后,下一步是把外部流量引进来——这归 ELB 管。
2. 入站流量:ELB 与 HTTPS
ELB(Elastic Load Balancing,弹性负载均衡)是 AWS 应用入口的事实标准。它把外部流量分发给后端 EC2、容器或 Lambda,承担 HTTPS 终止、健康检查、跨 AZ 容灾。
2.1 三种 ELB 选型决策
| 类型 | OSI 层 | 协议 | 典型场景 | 何时不选 | 价格量级 |
|---|---|---|---|---|---|
| ALB(Application Load Balancer) | L7 | HTTP / HTTPS / gRPC | Web 应用、微服务路径/Host 路由、WebSocket、Lambda target | 极致低延迟、TCP 直通、需要静态入口 IP | $0.0225/h + $0.008/LCU |
| NLB(Network Load Balancer) | L4 | TCP / UDP / TLS | 高并发长连接、游戏、DB 代理、需要静态 IP(每 AZ 一个 EIP)、TLS 透传 | 需要 HTTP 路由 / Host / Path | $0.0225/h + $0.006/NLCU |
| CLB(Classic Load Balancer) | L4 / L7 | HTTP / TCP | 仅老系统兼容 | 新项目一律不选 | $0.025/h + $0.008/GB 数据处理 |
实操原则:99% 的新项目从 ALB 起手;只有当应用是纯 TCP/UDP(如游戏、自建 DB 代理)或要求静态入口 IP 时才考虑 NLB;CLB 已是历史遗留,新项目不要碰。
💰 ALB 计费:$0.0225/h + $0.008/LCU-h。LCU(Load Balancer Capacity Unit,负载均衡容量单元)按 4 维度取最高维计费:每秒新建连接 25、活动连接 3,000、处理流量 1 GB/h、规则评估 1,000/s。一个轻量 Web 应用通常每月 $20-30 起步。
来源:AWS ELB Pricing
2.2 ELB → Target Group → Targets 三层关系
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart LR
User["用户请求"] --> ALB["ALB"]
ALB --> |"/api/*"| TG1["API Target Group"]
ALB --> |"/web/*"| TG2["Web Target Group"]
TG1 --> EC2A["EC2-API-1"]
TG1 --> EC2B["EC2-API-2"]
TG2 --> EC2C["EC2-Web-1"]
TG2 --> EC2D["EC2-Web-2"]
classDef alb fill:#3B82F6,stroke:#2563EB,color:#fff
classDef tg fill:#10B981,stroke:#059669,color:#fff
classDef ec2 fill:#F59E0B,stroke:#D97706,color:#fff
class ALB alb
class TG1,TG2 tg
class EC2A,EC2B,EC2C,EC2D ec2ALB 不直连 EC2,而是通过 Target Group(目标组)解耦。一个 ALB 可以根据路径或 Host 把流量分给不同 Target Group;同一个 Target Group 也可以同时挂在多个 ALB 上。Target Group 内部按健康检查筛选可用 target,再按算法(轮询 / 最少未完成请求)分发流量。这层解耦让蓝绿发布、按路径拆服务、共享后端实例等场景都很自然——只换 Target Group 的成员,不动 ALB 本身。
2.3 Target Group 与健康检查
Target Group 配置示例(YAML 风格伪码,仅示意字段结构,非 CloudFormation/Terraform):
1 | target_type: "IP addresses" # 或 instance(按实例 ID)/ lambda |
健康检查关键决策:
path指向轻量、不触发副作用的端点(如/healthz/readiness),不要用/——首页可能很重或带统计副作用,把 ALB 的探活流量误算进 PVmatcher默认 200,业务有 302 / 204 等正常响应时记得放宽到200-299或显式列出interval×unhealthy_threshold≈ 故障摘除时间。30 s × 2 = 60 s 是合理起步;过短会被瞬时抖动误摘,过长则故障实例久久无法剔除- 负载均衡算法:轮询(Round Robin,默认)/ 最少未完成请求(Least Outstanding Requests);后者更适合后端处理时长差异大的场景
2.4 创建 ALB
监听器(Listener)配置示例(YAML 风格伪码,仅示意字段结构,非 CloudFormation/Terraform):
1 | scheme: internet-facing # 或 internal(仅 VPC 内可达) |
CLI 创建 ALB(前置:已有 VPC、跨 AZ 公有子网、ALB 安全组、Target Group;已配置 awscli,IAM 拥有 elasticloadbalancing:CreateLoadBalancer 权限):
1 | aws elbv2 create-load-balancer \ |
2.5 HTTPS 与 ACM 证书
最常见的模式:浏览器 ↔ ALB 走 HTTPS(TLS 1.3),ALB 在边界处终止 TLS,转给后端 EC2 走 HTTP(VPC 内)。理由:
- 证书集中在 ALB 管理,无需在每台 EC2 配置和续签
- TLS 解密耗 CPU,由 ALB 集中处理,后端 EC2 节省算力
- VPC 内部网络已是受信环境(AWS 物理隔离 + 你自己的 SG / NACL 控制),HTTP 足够
- 后端只需监听 80 端口,配置最简
ACM(AWS Certificate Manager,证书管理器)申请要点:
- 在 us-west-2(与 ALB 同 Region)申请——ACM 证书是 Region 级资源,跨 Region 不可用。例外:CloudFront 必须用 us-east-1,详见第 6 章
- 推荐 DNS 验证(自动续订)而非邮箱验证(每年要手动确认,错过即过期)
- 公有证书对接 ALB / CloudFront / API Gateway 等 AWS 服务完全免费
💰 ACM 公有证书:免费(仅在对接 AWS 集成服务时;可导出证书 $7/年起,通配符 $79/年)。
来源:AWS Certificate Manager Pricing
2.6 安全组最佳实践:SG 引用而非 CIDR
新手常见做法:把 EC2 SG 入站 80 端口的 source 设为 0.0.0.0/0,让 ALB 来连。这意味着任何人只要拿到 EC2 公网 IP 就能直接连后端,绕过了 ALB——健康检查、HTTPS、WAF 全部失效。
正确做法:把 EC2 SG 入站 source 设为 ALB 的 SG(SG 互引用,AWS 原生支持,下方 YAML 风格伪码仅示意字段结构):
1 | # ALB SG |
效果:即使 EC2 有公网 IP,外部也无法绕过 ALB 直连——因为 EC2 SG 入站只放行了 ALB SG 成员。这是 VPC 内部「零信任」模式的最小落地,也是新手到生产实践的关键一步。
💡 进阶 / 成本:ALB 的 LCU 4 个维度按最高维计费——意味着如果你的应用规则评估很多(如 50+ 条 host / path 规则),即使流量小也会被「规则评估」维度顶到很高的 LCU。省钱方向:合并通配符规则、把高频路由放前面(前 10 条规则免费)、对长尾业务考虑用单独的 ALB 隔离 LCU 计费、避免在单条规则里塞过多条件触发额外评估。
2.7 常见踩坑
健康检查一直 unhealthy 但服务能访问
- 现象:浏览器访问 ALB 域名能正常打开页面,但 Target Group 一直显示所有 target unhealthy
- 根因:EC2 SG 入站 source 写的是 CIDR 而不是 sg-alb,且 ALB 节点 IP 段没加进来;或健康检查路径返回 302 / 204,但 matcher 默认只接受 200
- 处理:EC2 SG 入站 source 改为
sg-alb;放宽 matcher 为200-299或显式列出200,302;确认健康检查路径在 EC2 本地curl localhost/<path>能拿到预期状态码
ACM 证书在 ALB 列表里看不到
- 现象:明明在 ACM 控制台看到证书已签发,但绑定 ALB 时下拉框找不到
- 根因:证书申请时选错了 Region(如在 ap-northeast-1 申请,但 ALB 在 us-west-2)
- 处理:删掉旧证书,在与 ALB 同 Region(us-west-2)重新申请——ACM 证书不能跨 Region 复制;CloudFront 例外,必须 us-east-1
80 端口直接 forward 而非 redirect 到 443
- 现象:用户访问
http://example.com没有被强制升级到 HTTPS,浏览器地址栏显示「不安全」 - 根因:80 端口监听器的默认 action 选了 forward 到 Target Group,而非 redirect 到 HTTPS:443
- 处理:在 ALB 80 端口监听器上把默认 action 改为
redirect → HTTPS:443,状态码用HTTP_301(永久重定向,便于浏览器与搜索引擎缓存)
- 现象:用户访问
入口流量解决了,下一个问题是出口:私有子网的实例怎么访问公网,又不开放公网入站?
3. 出站流量:NAT 与 VPC Endpoint
私有子网(Private Subnet)里的 EC2 想拉镜像、调外部 API、装系统包,需要一条到公网的出口,但又不能让公网直接连进来。AWS 给了三条路:NAT Gateway(NAT 网关)、NAT Instance(自建 NAT EC2)、VPC Endpoint(VPC 终端节点)。三者价格、场景、维护代价差别很大。
3.1 私网出公网的三条路
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart LR
EC2["私有子网 EC2"]
NATGW["NAT Gateway<br/>(公有子网)"]
NATIns["NAT Instance<br/>(公有子网)"]
VPCE["VPC Endpoint"]
IGW["Internet Gateway"]
Backbone["AWS 内部骨干网"]
Internet((Internet))
AWSSvc["S3 / DynamoDB<br/>SQS / KMS 等"]
EC2 --> |"路径 1"| NATGW
EC2 --> |"路径 2"| NATIns
EC2 --> |"路径 3"| VPCE
NATGW --> IGW
NATIns --> IGW
IGW --> Internet
VPCE --> Backbone
Backbone --> AWSSvc
classDef ec2 fill:#FEF3C7,stroke:#D97706,color:#92400E
classDef gw fill:#DBEAFE,stroke:#2563EB,color:#1E3A5F
classDef ok fill:#D1FAE5,stroke:#059669,color:#065F46
classDef bad fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D
class EC2 ec2
class NATGW,IGW,Backbone gw
class VPCE,AWSSvc ok
class NATIns bad何时用哪条:
- 想访问任意公网(GitHub、外部 API、包管理器仓库):生产用 NAT GW;测试/极小流量场景才考虑 NAT Instance
- 只想访问特定 AWS 服务(S3、DynamoDB、SQS、KMS、Secrets Manager 等):VPC Endpoint,省钱且延迟低,流量不出 AWS 骨干网
3.2 NAT Gateway 计费拆解
NAT GW 是出站流量的「按表收费的水龙头」,计费分两段:小时费 + 数据处理费。
💰 NAT Gateway:按小时 $0.045 + 按数据处理 $0.045/GB(us-west-2)。一个 100 GB/天流量的服务每月账单 ≈ $32.4(小时费 30×24×0.045)+ $135(数据处理 100×30×0.045)= 约 $167/月。
来源:AWS VPC Pricing
注意:NAT GW 的数据处理费是叠加在出向公网流量费之上。EC2 → 互联网 1 GB,账单上是 $0.045(NAT 处理)+ $0.09(互联网出向)= $0.135/GB。这是新手最容易忽略的「双重收费」。
💰 互联网出方向流量(叠加在 NAT 数据处理费之上):us-west-2 出向公网前 10 TB $0.09/GB,next 40 TB $0.085/GB,next 100 TB $0.07/GB,>150 TB $0.05/GB。每月有 100 GB 免费额度(聚合所有 AWS 服务和 Region)。
来源:AWS Data Transfer Pricing API JSON
3.3 NAT Gateway Vs NAT Instance
| 维度 | NAT Gateway(托管) | NAT Instance(自建 EC2) |
|---|---|---|
| 管理 | AWS 全托管,无需打补丁 | 自己运维 EC2 |
| 高可用 | 单 AZ 内冗余;多 AZ 需各部署一个 | 需手动配置 + Auto Scaling |
| 吞吐量 | 弹性 5–100 Gbps | 受所选实例规格限制 |
| 小时成本 | $0.045/h + $0.045/GB 数据处理 | 仅 EC2 实例费(如 t3.nano $0.0052/h) |
| 运维成本 | 几乎为零 | 高(OS 升级、Source/Dest Check 配置) |
| 适用 | 99% 生产场景 | 仅极低流量 / 学习实验 |
实操原则:生产一律用 NAT Gateway。NAT Instance 看起来更便宜,但单点故障 + 自维护成本远超那点节省。
3.4 VPC Endpoint:Gateway Vs Interface
VPC Endpoint 让你直接走 AWS 内部骨干网访问 AWS 服务,不经过 NAT GW 和互联网。分两类:
| 类型 | 支持服务 | 计费 | 工作方式 |
|---|---|---|---|
| Gateway Endpoint | 仅 S3、DynamoDB | 免费 | 在路由表加一条目标为 vpce-xxx 的路由 |
| Interface Endpoint(PrivateLink) | 大部分 AWS 服务(SQS / SNS / KMS / Secrets Manager / ECR / Lambda 等) | 按小时(每 AZ 一个 ENI)+ 按数据处理 $0.01/GB(前 1 PB) | 在子网创建一个 ENI(弹性网卡,带私有 IP),通过私有 DNS 路由请求 |
💰 Interface Endpoint 数据处理:$0.01/GB(前 1 PB),$0.006/GB(next 4 PB),$0.004/GB(>5 PB)。小时费请以 AWS PrivateLink Pricing 为准(页面未明示具体小时费数字,建议用 AWS Pricing Calculator 校验)。
来源:AWS PrivateLink Pricing
3.5 省钱场景:S3 / DynamoDB 走 Gateway Endpoint 绕过 NAT GW
假设你的应用频繁向 S3 上传日志,月流量 1 TB(1024 GB):
| 方案 | NAT GW 数据处理 | 互联网出向 | Gateway Endpoint | 月成本(仅流量) |
|---|---|---|---|---|
| 走 NAT GW | 1024 × $0.045 = $46 | 1024 × $0.09 = $92 | — | $138 |
| 走 Gateway Endpoint | — | — | 免费 | $0(NAT GW 小时费 $32.4 仍在) |
仅靠一个免费 Gateway Endpoint,每月省 $138。实战要点:在路由表里给 S3/DynamoDB 加一条目标为 vpce-xxx 的路由,应用代码无需改动,SDK 走默认 endpoint 即可被路由命中。
💡 进阶 / 容灾:NAT Gateway 在单 AZ 内自动冗余,但单 AZ 故障时该 AZ 内私有子网会失去出网能力。生产建议:每个 AZ 部署一个独立 NAT GW,对应 AZ 的私有子网路由表指向本 AZ 的 NAT GW。这样既消除跨 AZ 故障传播,又避免 NAT GW 处理跨 AZ 流量产生额外的 $0.01/GB 跨 AZ 流量费。代价是 NAT GW 数量翻倍(小时费 × N AZ)——3 AZ 部署的小时费基线就从 $32.4 涨到 $97.2/月,需要权衡可用性与成本。
3.6 常见踩坑
NAT GW 部署在私有子网导致无法工作
- 现象:建好 NAT GW 后,私有子网实例仍然无法访问公网
- 根因:NAT GW 必须放在公有子网(路由表含
0.0.0.0/0 → IGW),它本身需要走 IGW 才能联通互联网;放在私有子网等于让一个不能上网的人当你的网关 - 处理:把 NAT GW 重建到公有子网;私有子网的路由表
0.0.0.0/0 → nat-xxx不变
Interface Endpoint 配了但 SDK 还是走公网
- 现象:在 VPC 里加了 SQS 的 Interface Endpoint,但应用调 SQS 仍然走 NAT GW + 公网,账单上没看到流量下降
- 根因:创建 Endpoint 时没勾选「启用私有 DNS」(Private DNS),SDK 仍然解析到公共域名
sqs.us-west-2.amazonaws.com→ 命中默认路由走 NAT GW - 处理:编辑 Endpoint 启用 Private DNS;或在 SDK 里把 endpoint URL 显式指向
vpce-xxx-xxx.sqs.us-west-2.vpce.amazonaws.com
跨 AZ NAT GW 流量费暴涨
- 现象:单一 NAT GW 服务多个 AZ 的私有子网,月底账单跨 AZ 流量费比预期高很多
- 根因:NAT GW 在 AZ-a,私有子网 b、c 的实例出网时流量先跨 AZ 到 NAT GW($0.01/GB)再走 NAT GW 出向($0.045/GB + $0.09/GB),账单上有三段费用
- 处理:每 AZ 独立部署一个 NAT GW,路由表按 AZ 隔离指向本 AZ 的 NAT GW,消除跨 AZ 流量费
入口、出口、子网都画好了,接下来该把真正跑应用的「机器」放进去——EC2。
4. 计算:EC2 实例与存储
EC2(Elastic Compute Cloud,弹性计算云)是 AWS 上跑应用的根基——Web、数据库、批处理最终都落到一台 EC2 上。这一章按「选机型 → 启动方式 → 安全 → 自动化 → 远程登录 → 磁盘」六块展开。
4.1 实例族速查
| 族系 | 类型 | 典型场景 | 代表机型 | 特点 |
|---|---|---|---|---|
| T(Burstable) | 突发型 | 低流量 Web、开发测试、CI Runner | t3.medium、t4g.medium | CPU 积分制,闲时积累、忙时消耗 |
| M(General) | 通用型 | Web 应用、微服务、中等数据库 | m6i.large、m7g.large | CPU/内存均衡(1:4) |
| C(Compute) | 计算优化 | 视频编码、批量计算、HPC | c7g.large、c7i.large | CPU 强、内存少(1:2) |
| R(Memory) | 内存优化 | 内存数据库、缓存、Spark | r6i.large、r7g.large | 内存大(1:8) |
| X(High Memory) | 大内存 | SAP HANA、超大内存数据库 | x2iezn.metal | 内存极大(>1 TB) |
| G/P(GPU) | GPU 计算 | 机器学习、图形渲染 | g5.xlarge、p4d.24xlarge | NVIDIA GPU |
| I(Storage) | 存储优化 | NoSQL、数据仓库 | i4i.large | 本地 NVMe SSD |
带 g 后缀的是 ARM (Graviton):性价比比 Intel/AMD 同级别高 20-40%,绝大多数 Linux 应用可无痛迁移。
💰 EC2 实例按需价(us-west-2 Linux):t3.medium $0.0416/h(约 $30/月),m6i.large $0.0960/h(约 $69/月),c7g.large $0.0725/h(约 $52/月),r6i.large $0.1260/h(约 $91/月)。
来源:AWS EC2 On-Demand Pricing API JSON (us-west-2)
实操原则:先按内存/CPU 比例选族系(默认起手 M 族),再按性价比选代际(新代际优先 Graviton)。机型不必一步到位,跑稳几周后用 CloudWatch 看实际利用率再纵向调整。
4.2 AMI 与 Launch Template
AMI(Amazon Machine Image,亚马逊机器镜像)= 操作系统 + 预装软件 + 启动配置的快照。AWS 官方提供 Amazon Linux 2023、Ubuntu、Windows 等基础镜像;你也可以从一个跑好的 EC2 制作自定义 AMI。
Launch Template(启动模板)= AMI + 实例类型 + SG + IAM Role + user-data 等所有启动参数的封装,是 Auto Scaling Group(第 9 章)的前置基础。
为什么不直接「Launch Instance」?
- Launch Template 可版本化(v1 → v2 → vN),方便回滚
- ASG 必须基于 Launch Template 才能批量起实例
- 团队协作时一份模板共享,避免每人手动凑参数出错
CLI 创建 Launch Template(前置:已有 AMI ID、SG、IAM Instance Profile,IAM 拥有 ec2:CreateLaunchTemplate 权限):
1 | aws ec2 create-launch-template \ |
4.3 IMDSv2:把 SSRF 攻击堵死
IMDS(Instance Metadata Service,实例元数据服务)让 EC2 实例可以访问 http://169.254.169.254/ 拿到自己的元数据,包括临时 IAM 凭证。这意味着任何能在实例上发起 HTTP 请求的代码都能拿到凭证——典型威胁就是 SSRF(Server-Side Request Forgery,服务端请求伪造)。
Capital One 2019 年那次 1.06 亿用户数据泄露就是这条链:WAF 规则配错 → 攻击者发起 SSRF → 访问 IMDS 拿到 EC2 凭证 → 用这把 “ 钥匙 “ 读 S3。
IMDSv2 的解决方案是引入会话 token:调用方先 PUT 一个请求拿 token,再带 token GET 元数据。绝大多数 SSRF payload 只能发 GET,无法构造 PUT,从根上断了路径。
强制实例只允许 IMDSv2(前置:实例已存在;IAM 拥有 ec2:ModifyInstanceMetadataOptions 权限):
1 | aws ec2 modify-instance-metadata-options \ |
hop-limit 1 防止容器(多一跳)拿到元数据;如果你跑的是 ECS/EKS,按官方文档设为 2。新建实例时通过 Launch Template 默认就强制 IMDSv2,是最佳实践。
4.4 user-data:开机自动化
user-data 是 EC2 第一次启动时自动执行的脚本(root 权限),用来装软件、拉应用、写配置:
1 |
|
把这段脚本放进 Launch Template 的 UserData 字段(base64 编码),新起实例自动执行——配合 ASG,30 秒内一台新机器就能加入服务。
注意:user-data 默认只在首次启动执行;后续重启不会再跑。如果你需要每次启动都执行,配合 cloud-init 的 cloud-init-per 或 systemd unit 实现。
4.5 Session Manager:不开 22 端口的远程登录
传统 SSH 模式的痛点:必须给实例开 22 端口入站、管理 SSH key 分发、堡垒机维护成本。Session Manager(AWS Systems Manager 的功能)让你无需开任何端口就能登录实例。前置:实例已附带 AmazonSSMManagedInstanceCore 策略,且 SSM Agent 在跑(Amazon Linux 2 起默认安装)。
1 | aws ssm start-session --target i-0123456789abcdef0 --region us-west-2 |
工作原理:实例上的 SSM Agent 主动出站连到 SSM 服务(走 443),形成长连接。你的 CLI 通过 SSM API 把会话流量隧道过去。
安全收益:
- EC2 SG 完全可以不开 22 端口——零网络入站攻击面
- 不用管理 SSH key
- 所有会话被 CloudTrail 记录,操作可审计
- 可以基于 IAM 策略授权 “ 只能登录某些 tag 的实例 “
额外好处:私有子网实例不需要堡垒机也能登录(Agent 走 NAT GW 或 Interface Endpoint 出站连 SSM)。
4.6 磁盘扩容三步走
EBS 卷扩容是新手最常踩的 “ 操作分两层 “ 问题:先在 AWS 控制面把卷扩大,再在 OS 内部把分区和文件系统扩大。三步走(前置:实例正在运行;IAM 拥有 ec2:ModifyVolume 权限):
1 | # Step 1: AWS 控制面扩卷 |
只做 Step 1 不做 Step 2/3 的后果:df -h 看到磁盘还是原来大小,AWS 已经在多收费。
4.7 EBS 类型决策
| 类型 | 介质 | 基准 IOPS | 基准 Throughput | 价格量级 | 典型场景 |
|---|---|---|---|---|---|
| gp3(推荐通用) | SSD | 3,000(可加) | 125 MiB/s(可加) | $0.08/GB-月 + IOPS/Throughput 加成 | Web 应用、中小数据库 |
| gp2(旧通用) | SSD | 与卷大小挂钩(3 IOPS/GB) | 与卷大小挂钩 | $0.10/GB- 月 | 仅历史遗留,新建一律选 gp3 |
| io2(高性能) | SSD | 自定义(最高 256k) | 自定义 | $0.125/GB-月 + $0.065/IOPS- 月 | 大型生产数据库、低延迟关键应用 |
| st1(吞吐型 HDD) | HDD | 较低 | 高 | $0.045/GB-月 | 大文件顺序读写:日志、大数据 |
| sc1(冷归档 HDD) | HDD | 极低 | 较低 | $0.015/GB- 月 | 极少访问的归档 |
💰 EBS 价格:gp3 $0.08/GB-月 + $0.005/IOPS- 月(超出 3,000)+ $0.06/MB·s-月(超出 125);io2 $0.125/GB- 月 + $0.065/IOPS-月(前 32k IOPS);st1 $0.045/GB- 月;sc1 $0.015/GB- 月。这些是页面 example 措辞中的数字,未明示 us-west-2,请以 AWS Pricing Calculator 校验。
来源:AWS EBS Pricing
实操原则:99% 新项目选 gp3——比 gp2 便宜 20%,且 IOPS/Throughput 可独立调高,不用「为了 IOPS 多买容量」。
4.8 IOPS 与 Throughput
| 指标 | 定义 | 类比 | 影响 |
|---|---|---|---|
| IOPS(Input/Output Per Second) | 每秒读写操作次数 | 收费站每秒通过的车辆数 | 响应速度、小文件并发处理能力 |
| Throughput(吞吐量) | 每秒传输的数据量(MiB/s) | 高速公路的总车道宽度 | 大文件传输效率 |
OLTP 数据库受 IOPS 制约(小事务多);视频处理 / 日志归档受 Throughput 制约(大文件少)。gp3 的优势就是两者可独立加量,不必通过加卷大小间接拉高。
4.9 快照 Vs AMI
| 概念 | 内容 | 用途 |
|---|---|---|
| EBS 快照 | 仅一块卷的数据 | 数据备份、跨 Region 复制单卷 |
| AMI | 实例所有卷的快照 + 启动配置(实例类型、ENA、卷映射) | 整机备份、克隆实例、分发到多账户 |
跨 Region 复制 AMI 一行命令(前置:源 Region 有目标 AMI;IAM 拥有 ec2:CopyImage 权限):
1 | aws ec2 copy-image \ |
跨 Region AMI 复制是异地容灾的常见做法:主区故障时,备区已有最新镜像可立即拉起。
💡 进阶 / 成本:On-Demand 是默认按小时按量付费,最贵;想长期省钱有两条路。Reserved Instances(RI,预留实例):承诺 1 年或 3 年用某机型,省 30-60%,但绑定机型;Savings Plans(储蓄计划):承诺每小时付 $X 用任意 EC2/Fargate/Lambda,更灵活,省 27-66%。起步建议:跑稳 3 个月、机型相对固定的工作负载,买 1 年期 Compute Savings Plan,立省 1/3 账单。
4.10 常见踩坑
growpart 后
df -h不变- 现象:执行了
aws ec2 modify-volume把卷从 50 GB 扩到 100 GB,但实例里df -h仍显示 50 GB - 根因:只扩了 AWS 控制面的卷大小,没扩 OS 内的分区和文件系统
- 处理:依次
growpart /dev/nvme0n1 1(扩分区)+resize2fs或xfs_growfs(扩文件系统)
- 现象:执行了
IMDSv1 被 SSRF 利用偷走凭证
- 现象:应用日志里突然出现大量自己没发起的 S3 / DynamoDB 调用,账单异常
- 根因:实例允许 IMDSv1,应用层有 SSRF 漏洞,攻击者通过它访问 IMDS 拿到 IAM Role 临时凭证后调 AWS API
- 处理:立即 revoke 该 IAM Role 的临时凭证(IAM → 角色 → 撤销 active sessions);强制实例改 IMDSv2(
--http-tokens required);新实例通过 Launch Template 默认强制 IMDSv2
Launch Template 改了版本但 ASG 还在用旧版
- 现象:更新了 Launch Template 到 v2,新拉的实例还是 v1 的镜像/配置
- 根因:ASG 引用 Launch Template 时绑定了具体版本号(如 v1),不会自动跟随最新版
- 处理:在 ASG 里把 Launch Template 版本改为
$Latest或$Default;或显式更新 ASG 引用到 v2,再触发实例替换(rolling update)
EC2 跑起来了,但应用产生的图片、日志、备份不该堆在 EBS 上——那是对象存储 S3 的工作。
5. 对象存储:S3 进阶
S3(Simple Storage Service)是 AWS 最古老、使用率最高的服务,几乎每个账户都开了一个 bucket(桶)。但「会用 S3」和「用好 S3」差距很大——存储类、生命周期、桶策略/IAM/ACL、签名 URL、私有桶 + CloudFront 每一项都有讲究。这一章按「省钱 → 安全 → 性能」展开。
5.1 6 种存储类决策
| 存储类 | $/GB-月(us-west-2 首阶梯) | 最小存储期 | 最小对象大小 | 取回延迟 | 典型场景 |
|---|---|---|---|---|---|
| Standard | $0.023 | — | — | ms 级 | 热数据:网站静态资源、应用上传文件 |
| Standard-IA(Infrequent Access,低频访问) | $0.0125 | 30 天 | 128 KB | ms 级 | 月级访问:备份、日志归档 |
| One Zone-IA | $0.01 | 30 天 | 128 KB | ms 级 | 可重生的冷数据(容灾仍要 Standard-IA) |
| Glacier Instant Retrieval(即时取回) | $0.004 | 90 天 | 128 KB | ms 级 | 季度访问:医疗影像、新闻档案 |
| Glacier Flexible Retrieval(灵活取回) | $0.0036 | 90 天 | 128 KB | 分钟–小时 | 备份归档:年访问几次 |
| Glacier Deep Archive(深度归档) | $0.00099 | 180 天 | 128 KB | 12 小时 | 合规归档:7-10 年留存 |
💰 S3 存储类:从 Standard ($0.023/GB-月) 到 Glacier Deep Archive ($0.00099/GB- 月),价差最高 23 倍。1 TB 数据从 Standard 转到 Deep Archive,月省约 $22。
来源:AWS S3 Pricing API JSON
实操原则:
- 写完后 30 天内会再访问的:留 Standard
- 写完后多半不会再读的:转 Standard-IA
- 仅合规留存、几乎不会读的:转 Glacier Flexible 或 Deep Archive
- 用生命周期规则自动转储(见 5.3),不手动搬
5.2 基础操作:cp Vs Sync
1 | # 下载整个 path 下的对象 |
cp vs sync 的关键区别:
| 命令 | 行为 | 适用场景 |
|---|---|---|
aws s3 cp | 无条件复制所有文件,直接覆盖 | 单文件传输、强制重新上传 |
aws s3 sync | 仅复制新增/更新的文件;配合 --delete 删除目标多余文件 | 目录同步、增量备份 |
新手最常踩:用 aws s3 cp 覆盖整个目录,把 100 MB 文件每次都重传一遍——浪费时间和钱。同步类操作一律 sync。
5.3 生命周期规则
让 S3 按对象年龄自动转储/删除,是省钱主力工具。一份典型生命周期 JSON(30 天 → IA、90 天 → Glacier、365 天删除):
1 | { |
应用方式:
1 | aws s3api put-bucket-lifecycle-configuration \ |
关键决策:
- IA 类对小文件不划算——按最少 128 KB 计费,1 KB 文件存 IA 反而比 Standard 贵
- Glacier 类有最小存储期:转入后不到期就删,仍按最小期付费
- 复杂业务可用 Intelligent-Tiering(智能分层):S3 自动按访问模式分层,省心但有少量监控费
5.4 桶策略 Vs IAM 策略 Vs ACL
| 工具 | 作用对象 | 适合场景 | 推荐度 |
|---|---|---|---|
| IAM 策略 | IAM 用户 / 角色 | 「我的应用能否读这个 bucket」——权限挂在主体上 | ⭐⭐⭐ 默认首选 |
| 桶策略(Bucket Policy) | 桶本身 | 「这个 bucket 能被谁访问」——跨账户访问、CloudFront OAC、公开静态站点 | ⭐⭐⭐ 跨边界场景必用 |
| ACL(Access Control List,访问控制列表) | 桶或对象 | 历史遗留:单对象级控制 | ⭐ 基本不要用,AWS 自己也在推荐关掉 |
实操:账户内部访问全用 IAM 策略;跨账户、对接 AWS 服务(CloudFront、Lambda)用桶策略;ACL 在创建桶时直接选「Bucket owner enforced」(桶所有者强制)禁用即可。
5.5 签名 URL:临时下发上传/下载凭证
签名 URL(Presigned URL,预签名 URL)= 一段带签名的临时链接,任何人拿到就能访问对应对象,不需要 AWS 凭证。常见用途:让前端直传文件到 S3,不经过你的服务器中转。
生成上传签名 URL(Go SDK v2 示例):
1 | // 前置:已配置 AWS 凭证;s 是包含 *s3.PresignClient 的 service struct |
生成下载签名 URL:
1 | obj, err := s.preSignClient.PresignGetObject(ctx, &s3.GetObjectInput{ |
安全要点:
- 时效尽量短(5-15 分钟);越长泄露风险越大
- 不要把签名 URL 写日志(默认 SDK 不写,但自定义 logging 中间件可能会)
- 私密文件下载建议每次访问重新签发而非缓存
5.6 S3 Transfer Acceleration(加速模式)
Transfer Acceleration(传输加速)把上传/下载流量经过 CloudFront 边缘节点中转,给跨地域大文件传输加速:
1 | obj, err := s.preSignClient.PresignPutObject(ctx, &s3.PutObjectInput{ |
启用顺序:先在桶上启用 Transfer Acceleration → 再上线代码(避免代码调用未启用的桶报错)。
关闭顺序:先下线代码 → 再关闭桶上的 Transfer Acceleration。
加速本身要额外收费(约 $0.04/GB),收益要看实际地理跨度。经验法则:用户与桶不同大陆、单文件 > 100 MB 时,加速明显;同 Region 内部上传不用开。
5.7 私有桶 + CloudFront OAC
让桶完全 Block all public access(屏蔽所有公开访问),但允许 CloudFront 通过 OAC(Origin Access Control,源访问控制)访问:
1 | { |
OAC 是 OAI(Origin Access Identity,源访问身份,旧版)的替代品,2022 年起推荐使用。用 OAC 后:
- 桶可以彻底关闭公网访问
- CloudFront 边缘节点用 SigV4(AWS 签名版本 4)签名访问 S3,安全且统计完整
- Condition 限定来源 distribution 防止「借桥」(其他 CloudFront 分发借用你的桶)
💡 进阶 / 安全:开启桶版本控制(Versioning)后,每次覆盖或删除对象都保留旧版本,可恢复误操作。配合 MFA Delete(多因素认证删除,要求删除版本时通过 MFA 二次验证),即使 IAM 凭证泄露,攻击者也无法永久删除数据。代价:旧版本占存储空间,需配生命周期规则自动清理 N 天前的旧版本。
5.8 常见踩坑
S3 OAC 配错策略导致 CloudFront 返回 403
- 现象:私有桶 + CloudFront 部署后,访问 CDN 域名一直 403
- 根因:桶策略 Condition 的 SourceArn 写错(distribution ID 不对、ARN 格式错误),或忘了把 Block all public access 中「阻止公开桶策略」那项放开
- 处理:核对 distribution ID;Block public access 4 项里只勾「阻止 ACL 公开」和「阻止公开 ACL」,让「通过桶策略授权」放行
生命周期转 IA 但小文件多反而更贵
- 现象:开启 30 天 → IA 规则后,账单不降反升
- 根因:bucket 里大量 < 128 KB 的小文件,IA 按 128 KB 起步计费 + 还有 $0.01/1000 次的转换 API 费
- 处理:转 IA 前先用 S3 Storage Lens(存储分析)看文件大小分布;小文件多的桶不开 IA,或先做对象合并(如把零散日志打包成 Parquet)
签名 URL 时效设太长被泄露
- 现象:用户反馈一个文件下载链接被陌生人下载;查日志发现签名 URL 过期时间 7 天
- 根因:开发图省事把 Expires 设成 7×24×3600 秒;用户分享链接到群聊或被搜索引擎抓走
- 处理:上传链接 ≤ 15 分钟、下载链接 ≤ 5 分钟;前端「下载」动作每次重新请求后端签发;敏感对象额外要求登录态校验
S3 解决了「存到哪」,下一步是「怎么让全球用户读得快」——CDN 上场。
6. 内容分发:CloudFront
CloudFront 是 AWS 的 CDN(Content Delivery Network,内容分发网络),把静态资源缓存到全球 600+ 边缘节点。用户从最近节点拿内容,既把首字节时间压到几十毫秒,也大幅降低源站(Origin)出向带宽费。
6.1 工作原理:用户 → 边缘节点 → 源站
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart LR
User["用户浏览器"] -->|"请求"| Edge["最近的 CloudFront<br/>边缘节点"]
Edge -->|"缓存命中"| User
Edge -.->|"缓存未命中"| Origin["源站<br/>(S3 / ALB / 自定义)"]
Origin -.->|"返回内容"| Edge
Edge -.->|"缓存 + 返回"| User
classDef user fill:#FEF3C7,stroke:#D97706,color:#92400E
classDef edge fill:#3B82F6,stroke:#2563EB,color:#fff
classDef origin fill:#10B981,stroke:#059669,color:#fff
class User user
class Edge edge
class Origin originDNS 把 CDN 域名解析到离用户最近的边缘节点(Edge Location)。命中时直接返回,未命中才回源拉取并顺带缓存到本节点。典型静态站点接入后缓存命中率(Cache Hit Ratio)通常 80-95%——源站只扛 5-20% 的请求,S3 出向流量、ALB LCU、EC2 CPU 都跟着下降。CloudFront 既加速响应,也省源站带宽费,是「内容能缓存」类应用的默认起手式。
6.2 缓存策略三件套
CloudFront 的「缓存键」(Cache Key)由三件套 Policy 共同决定,是命中率的关键:
| Policy | 作用 | 关键字段 |
|---|---|---|
| Cache Policy(缓存策略) | 决定缓存键 + TTL(Time To Live,缓存有效期) | 是否包含 Query String、Header、Cookie;min/max/default TTL |
| Origin Request Policy(源请求策略) | 决定哪些信息转发到源站(不影响缓存键) | Header、Query String、Cookie |
| Response Headers Policy(响应头策略) | 给响应加/改 Header | CORS、Strict-Transport-Security、Cache-Control 等 |
默认起手三件套:
- Cache Policy 选 AWS 托管的
Managed-CachingOptimized(不带 Cookie / Query String,TTL 24 h)——绝大多数静态资源够用 - Origin Request Policy 默认即可
- Response Headers Policy 加一个
SecurityHeadersPolicy(一键开 HSTS、X-Frame-Options 等安全头)
误区:把 Cache Policy 配成「转发所有 Cookie / All Headers」。缓存键会随每个用户的 sessionid / UA 爆炸膨胀,命中率骤降到接近 0——CloudFront 等于白开。Cookie / Header 转发只在确需个性化的资源(如登录后页面)开启,并用单独的 Cache Behavior 限定到特定路径。
6.3 域名绑定与 ACM 证书
把 cdn.example.com 绑到 CloudFront 分发的步骤:
- 在 us-east-1 申请 ACM 证书(注意不是 ALB 所在 Region,原因见 6.4)
- CloudFront 分发设置 → SSL/TLS → 选刚签发的证书
- 添加 Alternate domain name(CNAME 别名):
cdn.example.com - DNS 服务商创建 CNAME 记录:
cdn.example.com → dxxxxxx.cloudfront.net - 等几分钟全球边缘节点生效
CLI 验证证书已在 us-east-1 就绪(前置:已配置 awscli,IAM 拥有 acm:ListCertificates 权限):
1 | # CloudFront 强制证书在 us-east-1,CLI 也必须显式指定该 Region |
6.4 为什么 CloudFront 证书必须在 Us-east-1
CloudFront 是全球服务:分发(Distribution)配置由 AWS 全球控制面统一管理,而控制面的物理实例就在 us-east-1(弗吉尼亚)。证书要被全球边缘节点统一拉取使用,就必须放在控制面所在的 ACM Region——也就是 us-east-1。其它 Region 的 ACM 证书 CloudFront 根本看不到。
对比:ALB 是 Region 级资源,证书必须与 ALB 同 Region。新手最容易混的两条路:
- 应用域名(指向 ALB)→ 证书在 ALB 所在 Region(如 us-west-2)
- CDN 域名(指向 CloudFront)→ 证书必须在 us-east-1
如果偷懒只在 us-east-1 申请一张,ALB 用不了——ACM 证书不能跨 Region 引用。生产实践通常是:同一个域名在 us-east-1 与 ALB 所在 Region 各申一张,DNS 验证共用同一组 CNAME 记录。
6.5 缓存失效(Invalidation)
更新源站资源后,需要强制让 CloudFront 重新回源拉取(不然全球边缘节点还在按 TTL 返回旧版本):
- 控制台:分发详情页 → Invalidations → Create Invalidation
- 输入路径:
- 单个对象:
/path/to/object.jpg - 整个目录:
/static/css/* - 全部失效:
/*(紧急情况用,慎用)
- 单个对象:
CLI 一键失效(前置:已配置 awscli,IAM 拥有 cloudfront:CreateInvalidation 权限):
1 | # CloudFront 命令统一带 --region us-east-1 |
💰 CloudFront 失效:每月前 1,000 路径免费,超出后 $0.005/路径(全球统一价)。频繁全量失效(
/*)只算 1 个路径,但会让全球缓存命中率瞬间归零、源站压力瞬时暴涨——慎用。
来源:AWS CloudFront Pricing
💰 CloudFront 流量:北美 / 欧洲 edge 出向每月前 1 TB 免费(永久免费层,不限月份),超出后北美/欧洲约 $0.085/GB。HTTPS 请求每月前 1,000 万次免费,超出后 $0.0100 / 10,000 次。
来源:AWS CloudFront Pricing
最佳实践:版本化文件名替代失效。把 app.css 改成 app.v1.2.3.css——加版本号即新文件,永远不需要失效;CI/CD 构建时自动注入 hash(如 app.[contenthash].css),从根上免去失效操作。
6.6 CloudFront Functions Vs Lambda@Edge(边缘计算决策表)
CloudFront 支持两种边缘计算选项,差别巨大,选错会多花 100 倍钱:
| 维度 | CloudFront Functions | Lambda@Edge |
|---|---|---|
| 运行时 | JavaScript(轻量 V8 引擎) | Node.js / Python |
| 触发点 | viewer-request / viewer-response(2 个) | viewer-request / viewer-response / origin-request / origin-response(4 个) |
| 执行时长上限 | < 1 ms | < 5 s(viewer 触发)/ 30 s(origin 触发) |
| 内存 | 2 MB | 128 – 10,240 MB |
| 包大小 | 10 KB | 1 – 50 MB |
| 价格量级 | 极低($0.10 / 百万次调用) | 较高(按 Lambda 标准 + 边缘溢价) |
| 能否调外部 API / 网络 IO | 否 | 是 |
| 典型用途 | URL 改写、Header 修改 / 加签、A/B 简单分流、SEO 跳转 | 鉴权(JWT 验证)、ESI 拼装、调用外部 API、复杂路由、个性化响应 |
实操原则:能用 CloudFront Functions 做的就别用 Lambda@Edge——便宜 100×、延迟低 10×。只有需要调外部 API 或复杂逻辑(如 JWT 解析 + 远程鉴权)才上 Lambda@Edge。两者也可以配合:viewer-request 用 Functions 做轻量改写,origin-request 用 Lambda@Edge 做重逻辑。
💡 进阶 / 可观测:CloudFront 访问日志(Standard Logs)可写到 S3 桶,每条记录含 viewer IP、URI、状态码、传输字节、
x-edge-result-type(缓存命中状态)等字段。配合 Athena(基于 S3 的 Serverless SQL 查询服务)一行 SQL 即可查「过去 1 小时 5xx 来源 Top 10」或「缓存命中率最低的 10 个 URL」。建表语句和典型查询模板见 AWS 官方指南。日志写入 S3 免费(仅占用存储费),Athena 查询按扫描数据量 $5/TB 计费,按日期分区可把单次查询压到几分钱。
6.7 常见踩坑
改了 S3 内容但 CDN 没失效,用户拿到旧版本
- 现象:S3 里更新了
style.css,浏览器仍加载旧样式,强刷也无效 - 根因:CloudFront 默认按 Cache Policy 的 TTL 缓存(
Managed-CachingOptimized默认 24 h),不会自动感知源站变化 - 处理:发布流程加
aws cloudfront create-invalidation --paths /style.css --region us-east-1;更稳妥的方案是改用版本化文件名(style.v1.2.3.css),CI 构建时用 contenthash 自动生成
- 现象:S3 里更新了
Cache Policy 把 Cookie 全转发,命中率接近 0
- 现象:开了 CloudFront 但源站流量几乎没降,命中率长期 < 5%
- 根因:Cache Policy 配了「All Cookies」转发到缓存键,每个用户的
sessionid/_ga不同 → 缓存键不同 → 资源几乎不被复用 - 处理:改用
Managed-CachingOptimized(不含 Cookie / Header);某些路径确需个性化(如/account/*)就单独建一个 Cache Behavior 仅对这些路径转发指定 Cookie
证书在 ap-northeast-1 申请,CloudFront 列表里看不到
- 现象:在 us-east-1 之外的 Region 申请了 ACM 证书,CloudFront 域名设置下拉框找不到
- 根因:CloudFront 强制要求证书在 us-east-1,跨 Region 不识别
- 处理:在 us-east-1 重新申请同域名证书;DNS 验证 CNAME 可与原证书共用同一组记录
静态资源的分发讲完了,接下来是动态数据的家——关系数据库。
7. 关系数据库:RDS
RDS(Relational Database Service)是 AWS 托管的关系数据库。你只管 schema、SQL、索引;AWS 负责打补丁、备份、监控、主备切换这些「机房 DBA」的活。
7.1 引擎选择:MySQL / PostgreSQL / Aurora
| 引擎 | 兼容性 | 性能 | 存储扩展 | 典型场景 | 起步成本 |
|---|---|---|---|---|---|
| RDS MySQL | 原生 MySQL,社区生态最广 | 中等 | 手动加卷 | 中小项目、与开源工具无缝 | db.t3.medium 单 AZ $0.068/h |
| RDS PostgreSQL | 原生 PostgreSQL | 中等 | 手动加卷 | 复杂查询、JSONB、地理空间 | 同量级 |
| Aurora MySQL/PG | 兼容 MySQL/PG | 高(约 RDS 3-5×) | 自动扩到 128 TB | 中大型生产、读写分离要求高 | 比同规格 RDS 略高,请以 AWS Pricing Calculator 为准 |
💰 RDS MySQL(us-west-2):db.t3.medium 单 AZ $0.068/h(约 $49/月)、Multi-AZ $0.136/h(精确 2×);db.m6i.large 单 AZ $0.171/h(约 $123/月)、Multi-AZ $0.342/h;备份存储超出免费额度部分 $0.095/GB- 月。
来源:AWS RDS Pricing API JSON (us-west-2)
实操:个人 / 小项目用 RDS MySQL 或 PostgreSQL 起 t3 类;中大型生产关心 P99 延迟和读写分离用 Aurora。
7.2 创建数据库实例
1 | # 前置:已有 VPC、隔离子网(数据层)、SG、Secrets Manager 中存好密码 |
要点:选隔离子网(无 0.0.0.0/0);SG 入站只放 EC2/应用 SG 作 source(不开 CIDR);--multi-az 立即开同步副本;--backup-retention-period 7 自动备份保留 7 天(最长 35)。
7.3 参数组:修改 max_connections
RDS 实例的参数(max_connections、innodb_buffer_pool_size 等)通过参数组修改,不能直接 SET GLOBAL。完整流程:
1 | # Step 1 创建自定义参数组 |
参数分 dynamic(修改即生效)和 static(必须重启):max_connections 是 dynamic、innodb_log_file_size 是 static。
7.4 备份机制:自动备份 Vs 手动快照
| 类型 | 触发 | 保留期 | 恢复粒度 | 用途 |
|---|---|---|---|---|
| 自动备份(Automated) | 每天一次完整备份 + 持续事务日志 | 1-35 天(实例删除后默认清除) | PITR(Point-in-Time Recovery,时间点恢复)到任意秒 | 日常容灾 |
| 手动快照(Manual Snapshot) | 用户主动触发 | 永久(直到手动删除) | 仅快照那一刻 | 升级/迁移前备份;长期归档 |
PITR 恢复示例:
1 | aws rds restore-db-instance-to-point-in-time \ |
关键:删除实例时默认会一并清掉自动备份;想保留得提前手动 snapshot。
7.5 Multi-AZ ≠ 只读副本
新手最常混淆这两个概念,它们解决的问题完全不同:
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart LR
subgraph MultiAZ ["Multi-AZ:高可用"]
AppA["应用"] --> Primary["主库 (AZ-a)<br/>读写"]
Primary -.->|"同步复制"| Standby["备库 (AZ-b)<br/>不可读"]
end
subgraph ReadReplica ["只读副本:读写分离"]
AppB["应用"] -->|"写"| Master["主库"]
AppB -->|"读"| RR1["只读副本 1"]
AppB -->|"读"| RR2["只读副本 2"]
Master -.->|"异步复制"| RR1
Master -.->|"异步复制"| RR2
end
classDef primary fill:#3B82F6,stroke:#2563EB,color:#fff
classDef standby fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D
classDef rr fill:#10B981,stroke:#059669,color:#fff
classDef app fill:#FEF3C7,stroke:#D97706,color:#92400E
class Primary,Master primary
class Standby standby
class RR1,RR2 rr
class AppA,AppB app| 维度 | Multi-AZ | 只读副本(Read Replica) |
|---|---|---|
| 复制方式 | 同步(强一致) | 异步(秒级延迟) |
| 备库可读 | 不可读(待命) | 可读(专门用来读) |
| 故障切换 | 自动 60-120 秒 | 手动提升为主库 |
| 解决的问题 | 高可用 | 读写分离、降低主库压力 |
| 计费 | 主备同价(约 2× 单 AZ) | 每个副本按实例费另算 |
典型生产架构:Multi-AZ + 多个只读副本——同时拿到高可用 + 读扩展。
7.6 只读副本与链式副本
1 | aws rds create-db-instance-read-replica \ |
链式副本(Chained Replication):从一个只读副本再起一个只读副本,形成级联结构。常见于跨 Region 容灾:主库 → 同 Region 副本 → 跨 Region 副本。
⚠️ 副本与主库共享相同用户名密码。若用 Secrets Manager 自动轮换密码,副本会自动同步。
7.7 Performance Insights:定位慢查询
Performance Insights 是 RDS 内置的性能分析工具:
- Top SQL:按等待时间排名当前最耗资源的 SQL
- 等待事件:CPU、IO、锁等各维度时间分布
- 保留期:免费 7 天;扩展到 2 年另收费
启用方式:创建实例时勾选 “Enable Performance Insights”,或后续 modify-db-instance --enable-performance-insights。新手用法:进控制台 RDS → 实例 → Performance Insights,鼠标点点就能定位 “ 哪条 SQL 占了 60% CPU”。
7.8 用户管理(MySQL)
1 | -- 创建读写用户 |
最佳实践:master 账号只用来建库建用户,应用一律用业务账号;按 “ 读/写/管理 “ 分至少 3 套账号。
7.9 Secrets Manager 自动轮换
把数据库密码放 Secrets Manager 而非配置文件:
- 应用启动时通过 SDK 拉密码(带缓存)
- Secrets Manager 可配置每 30 天自动轮换:调用 Lambda 函数生成新密码 → 更新到 RDS → 更新到 Secret
- 轮换期间新旧密码并存一段,靠 Secret 的
AWSPENDING/AWSCURRENT阶段标识区分
只读副本与主库共享主用户名密码——开了自动轮换后,主库密码改了,副本自动同步,应用层无感。
💡 进阶 / 容灾:单 Region 故障会让 Multi-AZ 也失效。生产关键库建议开启跨 Region 自动备份(Cross-Region Automated Backups):备份会异步复制到指定的备 Region,主 Region 整体故障时可在备 Region 用备份恢复。代价:跨 Region 备份存储费 + 跨 Region 流量费,按 GB 计;RPO 通常分钟级(取决于复制延迟)。
7.10 常见踩坑
修改参数组但实例没重启,参数没生效
- 现象:把
max_connections从 100 改到 500,应用仍报 “too many connections” - 根因:dynamic 参数确实立即生效,但首次关联自定义参数组到实例这步本身需要重启;或修改的是 static 参数(如
innodb_log_file_size)必须重启 - 处理:
SHOW VARIABLES LIKE 'max_connections'确认;若仍是旧值,reboot-db-instance
- 现象:把
误把 Multi-AZ 当读写分离用
- 现象:开了 Multi-AZ 想分流读流量到备库,结果连不上备库的 endpoint
- 根因:Multi-AZ 备库不对外可读,仅作待命;只读副本才可读
- 处理:开只读副本(Read Replica)做读写分离;Multi-AZ 解决的是 “AZ 故障自动切换 “
快照恢复后用户/参数组都没了
- 现象:从快照恢复一个新实例,发现自定义用户、参数组关联全丢失
- 根因:快照只包含数据;用户存在
mysql.user表里随快照走,但参数组关联和 SG 关联是实例级配置不在快照里 - 处理:恢复后立即
modify-db-instance重新关联参数组、SG、备份保留期等;写到 IaC 模板里避免漏
主库扛得住事务,但顶不住高频热点读——这就需要在 RDS 前面再加一层缓存。
8. 缓存与文档库:ElastiCache & MongoDB Atlas
缓存层和 NoSQL 文档库是 Web 应用常见的两个「侧路」组件。缓存做快路径:把热点数据从 DB 抬到内存,挡掉 80% 的读。文档库做灵活存储:schema 多变、嵌套结构、迭代快的业务对象。AWS 自家用 ElastiCache 覆盖前者;但没有原汁原味的托管 MongoDB(DocumentDB 兼容性有限),需走 Marketplace 订阅 MongoDB Atlas。
8.1 ElastiCache 三种形态决策
ElastiCache 现在有三种部署形态,先选形态再选引擎:
| 形态 | 自动扩缩 | 数据分片 | 适用 | 备注 |
|---|---|---|---|---|
| Serverless | 自动 | 自动 | 不想管节点;流量波动大 | 按 ECPU + 数据存储计费 |
| Cluster Mode Disabled | 手动 | 单分片 + 副本 | 小数据集(< 节点内存上限)、需 Redis 全部命令 | 类似自建 Redis 主从 |
| Cluster Mode Enabled | 手动 | 多分片(slot 分布) | 大数据集、高吞吐 | 客户端必须 cluster-aware |
💰 ElastiCache:Serverless 按 ECPU $0.0023/百万次(Valkey/Redis OSS)+ 数据存储 $0.084/GB·h(页面 example,未明示 us-west-2)。节点形态按实例小时费 + 备份存储 $0.085/GiB- 月(页面明确)。具体小时费请以 AWS Pricing Calculator 为准。
来源:AWS ElastiCache Pricing
8.2 Redis Vs Memcached
形态选完,再选引擎。AWS ElastiCache 同时支持 Redis(含 Valkey 这个开源 fork)和 Memcached:
| 维度 | Redis | Memcached |
|---|---|---|
| 数据结构 | 丰富(String/List/Hash/Set/Sorted Set/Stream/Geo) | 仅 String |
| 持久化 | RDB / AOF 可选 | 无 |
| 主从复制 | 原生支持 | 无(多线程多核) |
| 集群 | Cluster Mode | 客户端分片 |
| 多线程 | Redis 6+ I/O 多线程;命令仍单线程 | 原生多线程 |
| 典型用途 | 会话、计数器、排行榜、消息队列、限流 | 纯读缓存(缓存 SQL 结果、HTML 片段) |
实操:99% 新项目选 Redis——Memcached 只在 “ 我就要纯字符串多线程缓存 “ 的极致场景用。AWS 推荐用 Valkey(Redis 7.x 的开源 fork,与 Redis OSS 协议兼容,价格更低)。
8.3 ElastiCache Serverless 简介
Serverless 形态默认开启 Cluster Mode,数据自动分布到多个 AWS 内部分片:
- 无需选实例类型、节点数、副本数
- 容量自动扩缩,按实际使用计费
- 内置高可用(多 AZ)
适合流量波动大、不想运维节点的项目。注意:Serverless 不支持某些 Redis 管理命令(如 CONFIG SET),如果应用代码强依赖这些命令,先在测试环境验证兼容性。
创建命令:
1 | # 前置:已有 VPC、隔离子网、SG(开 6379 端口入站只放应用 SG) |
8.4 MongoDB Atlas:通过 Marketplace 订阅
虽然 AWS 没有自家的 “ 托管 MongoDB”(DocumentDB 兼容性有限),但可以通过 AWS Marketplace 直接订阅 MongoDB 官方的 Atlas,账单合并到 AWS:
- AWS Marketplace 搜 “MongoDB Atlas (pay-as-you-go)” → Subscribe
- View purchase options → 完成账户关联(跳到 Atlas 完成 OAuth)
- 在 Atlas 控制台创建 Cluster:
- 模式:Dedicated
- 实例类型:M10(2 GB RAM, 2 vCPU),生产建议 M30+
- 关闭:Global Writes、BI Connector(按需开)
好处:Atlas 账单按小时计入 AWS Bill,一处对账;MongoDB 官方支持比 DocumentDB 兼容性更全。
8.5 Atlas 网络打通:VPC Peering Vs PrivateLink
把应用 EC2 与 Atlas Cluster 私网联通的两种方式:
| 维度 | VPC Peering | PrivateLink |
|---|---|---|
| 配置 | 简单(双方接受请求即可) | 较复杂(需建 Endpoint Service) |
| 流量方向 | 双向 | 单向(消费者 → 提供者) |
| 跨账户 | 支持 | 支持 |
| 跨 Region | 支持(额外费) | 不支持 |
| 成本 | 仅 AWS 跨 AZ / 跨 Region 流量费 | 端点小时费 + 数据处理费 |
| IP 重叠 | 不能重叠 | 可重叠(无需 CIDR 协调) |
| 典型用途 | 你的 VPC 与 Atlas Cluster VPC 直连 | 多个独立 VPC 都要访问 Atlas,且不想协调 CIDR |
实操推荐:起步用 VPC Peering——配置简单、成本低;只有当多个独立项目要访问同一 Atlas Cluster 且 CIDR 难以协调时再上 PrivateLink。
💡 进阶 / 成本:缓存层主要成本是内存。省钱思路:(1) 给所有 key 设合理的 TTL(如
SETEX user:123 600 ...),自然过期不占内存;(2) 配置内存淘汰策略maxmemory-policy allkeys-lru,达到内存上限时自动淘汰最少使用的 key;(3) 大对象(> 1 MB)尽量序列化压缩或拆小存。反例:忘了 TTL,1 个月内存涨到爆,被迫升级实例规格——比一开始就配 TTL 贵几倍。
8.6 常见踩坑
ElastiCache Cluster Mode Enabled 客户端没用 cluster-aware SDK
- 现象:连 cluster 形态 Redis,调
GET偶尔报MOVED错误,命令失败 - 根因:cluster 模式下不同 key 分布在不同分片,普通 Redis 客户端只连一个节点,命中其它分片 key 时 Redis 返回 MOVED 重定向,但普通客户端不识别
- 处理:用支持 cluster 的客户端(go-redis 的
ClusterClient、Lettuce 的RedisClusterClient、ioredis 的Redis.Cluster);或改用 Cluster Mode Disabled 形态
- 现象:连 cluster 形态 Redis,调
Atlas 默认 0.0.0.0/0 IP 白名单忘改
- 现象:Atlas Cluster 创建后任何 IP 都能连,被扫描器找到后字典攻击数据库
- 根因:Atlas 创建向导默认 IP Access List 为
0.0.0.0/0(所有 IP),便于初始连接测试 - 处理:建好后立即在 Atlas → Network Access 把
0.0.0.0/0删掉,改为 VPC Peering 后自动生效的私有 CIDR;或精确白名单办公出口 IP
VPC Peering 后两侧路由表都要加路由
- 现象:Peering 状态显示 “Active”,但 EC2 ping 不通对端 VPC 内的 IP
- 根因:Peering 只是建立 “ 关系 “,两侧 VPC 的路由表都需要手动加目标为对端 CIDR、target 为 pcx-xxx 的路由,否则流量不知道怎么走
- 处理:在双方 VPC 的所有相关路由表里都加上对端 CIDR → pcx-xxx 的路由
数据层的容量与缓存解决了,回过头看应用层——固定数量的 EC2 撑不起波动的流量,下一章把它变弹性。
9. 弹性伸缩:Auto Scaling Group
流量随时间天然波动:白天高夜里低、周末高工作日低、活动瞬间冲峰。固定数量 EC2 只有两条糟糕选择:按峰值配,平时大量算力闲置;按均值配,高峰扛不住 5xx。Auto Scaling Group(ASG)让实例数量随指标自动伸缩,配合 ALB 既弹性又高可用。
9.1 ASG 三件套:Launch Template + ASG + Scaling Policy
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart LR
LT["Launch Template<br/>(AMI + 实例类型 + SG + IAM Role + user-data)"]
ASG["Auto Scaling Group<br/>(min/desired/max + 子网 + 健康检查)"]
SP["Scaling Policy<br/>(目标追踪 / 步进 / 计划)"]
EC2["EC2 实例 × N"]
LT --> ASG
SP --> ASG
ASG -->|"按需起/停"| EC2
classDef lt fill:#FEF3C7,stroke:#D97706,color:#92400E
classDef asg fill:#3B82F6,stroke:#2563EB,color:#fff
classDef sp fill:#10B981,stroke:#059669,color:#fff
classDef ec2 fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D
class LT lt
class ASG asg
class SP sp
class EC2 ec2简短解释三件套:
- Launch Template 是 “ 实例长什么样 “ 的模板(详见第 4 章 4.2 节)
- ASG(Auto Scaling Group)是 “ 我要 N 台实例分布在哪些子网 “ 的容器:min(最少)/ desired(期望)/ max(最多)
- Scaling Policy 是 “ 什么时候改 desired” 的规则
ASG 自动维持 desired 数量的健康实例:有实例挂了自动起新的,触发扩容时自动起更多。
💰 ASG 本身不收费:只为底层 EC2 实例付费(按第 4 章实例族单价)。ASG 多起实例时,账单跟着加;缩到 0 时账单为 0(仅留 Launch Template / 空 ASG 不计费)。
来源:AWS Auto Scaling Pricing
9.2 与 ALB Target Group 自动注册
ASG 的关键价值之一:新起的实例自动注册到指定 Target Group,缩容时自动注销。这让 ALB 始终把流量指向当前活着的实例集合,无需人工运维。
配置方式:创建 ASG 时指定 --target-group-arns arn:...:targetgroup/my-tg。新实例 launch 后通过健康检查 → 自动加入 TG → 接收流量;scale-in 时反向流程。
9.3 扩缩策略选型
| 策略 | 触发方式 | 适用场景 | 配置复杂度 |
|---|---|---|---|
| Target Tracking(目标追踪) | 维持指标在目标值(如 CPU 平均 50%) | 通用首选——大部分应用 | ⭐ 低 |
| Step Scaling(步进) | 按指标阈值阶梯扩缩(CPU > 70% 加 2 台、> 90% 加 4 台) | 需对突发流量分级响应 | ⭐⭐ 中 |
| Scheduled(计划) | 按时间表(每天 9 点扩到 10 台、22 点缩到 2 台) | 已知流量模式(早高峰、定时批处理) | ⭐ 低 |
| Predictive(预测) | ML 预测未来 48 小时流量 | 周期性强、ML 友好场景 | ⭐⭐⭐ 高 |
实操原则:99% 项目用 Target Tracking——目标值设 50% 给突增留 buffer,简单稳健。Step Scaling 仅在已观察到 Target Tracking 反应不够及时时上。
9.4 EC2 健康检查 Vs ELB 健康检查
ASG 判定实例健康的两种方式:
| 类型 | 检查内容 | 失败后的动作 |
|---|---|---|
| EC2 健康检查(默认) | 实例是否运行(pending / running / stopped 等) | 仅在实例本身停了才替换 |
| ELB 健康检查 | ALB Target Group 健康检查的结果(应用响应是否健康) | 应用挂了即使实例还活着也会被替换 |
关键决策:生产强烈建议开 ELB 健康检查。典型场景:应用进程死了但 OS 还活着,EC2 检查觉得「实例 running 一切正常」;ELB 检查发现「应用 5xx」,触发实例替换。
CLI 启用:
1 | aws autoscaling update-auto-scaling-group \ |
grace-period 300:实例新起后给应用 5 分钟冷启动时间再开始 ELB 健康检查,避免冷启动期被误判。
9.5 生命周期钩子:优雅上线与下线
生命周期钩子(Lifecycle Hook)让你在实例进入运行前或终止前插入自定义动作:
- EC2_INSTANCE_LAUNCHING:新实例 pending 后、加入 TG 前——可用于预热缓存、注册到服务发现
- EC2_INSTANCE_TERMINATING:缩容触发后、实例真正终止前——用于优雅下线(停接新连接、等老连接完成、上传日志)
典型用法:
1 | aws autoscaling put-lifecycle-hook \ |
实例进入终止前会停在 Terminating:Wait 状态最多 5 分钟,期间应用可调 complete-lifecycle-action 主动告知 “ 我准备好了 “ 或自动 5 分钟后继续终止。
9.6 创建 ASG(CLI 示例)
1 | # 前置:已有 Launch Template、跨 AZ 私有子网、Target Group |
注意 Version=\$Latest 让 ASG 自动跟随 Launch Template 最新版本(详见踩坑 3)。
💡 进阶 / 踩坑:扩容触发后从 “ 启动新实例 “ 到 “ 实例通过健康检查、加入 TG 接流量 “ 通常 2-5 分钟(拉镜像、跑 user-data、应用冷启动),这段时间叫冷启动延迟。瞬时大流量场景可能来不及响应。Warm Pool:预先起一批已完成 user-data 但停在 stopped 状态的实例,扩容时直接 start,把冷启动从分钟级降到秒级。代价是这些 stopped 实例仍按 EBS 存储付费。配置方式:
aws autoscaling put-warm-pool --auto-scaling-group-name ... --max-group-prepared-capacity 5 --pool-state Stopped。
9.7 常见踩坑
用 EC2 健康检查导致应用挂了但实例没替换
- 现象:应用进程 OOM 退出几小时,ALB 5xx 暴增,但 ASG 没替换实例
- 根因:默认 health-check-type 是 EC2,只看实例 running 状态;应用进程挂了实例还在 running,ASG 不动
- 处理:
update-auto-scaling-group --health-check-type ELB;同时把 ALB Target Group 的健康检查路径设为应用真实就绪端点(如/readiness检查依赖项)
缩容时丢失正在处理的请求
- 现象:ASG 缩容后用户报 504 Gateway Timeout,日志显示部分请求处理一半被中断
- 根因:实例直接 SIGKILL,没等 ALB 把流量切走;或缺生命周期钩子做 “ 优雅下线 “
- 处理:开 EC2_INSTANCE_TERMINATING 钩子 + ALB Target Group 开 Connection Draining(默认 300 秒);应用监听 SIGTERM 信号,停接新请求等老请求完成再退出
Launch Template 改了版本但 ASG 还引用旧版本
- 现象:把 Launch Template 升到 v3(新 AMI、新 user-data),但 ASG 新起的实例还是 v2 的镜像
- 根因:ASG 引用 Launch Template 时绑定了具体版本号
Version=2,不会自动跟随最新版 - 处理:把 ASG 的 LaunchTemplate 引用改为
Version=$Latest;或显式update-auto-scaling-group更新到 v3,再触发 instance refresh(rolling update)
弹性伸缩之后,整套架构跑起来了。但跑得对不对、性能怎样、出错的地方在哪——这是最后一块基础设施:可观测性。
10. 可观测性:CloudWatch
CloudWatch 是 AWS 原生可观测三件套:Logs(日志)、Metrics(指标)、Alarms(告警)。跑生产应用的账号都该开起来——不开等于「应用挂了你才从用户工单里发现」。
10.1 三件套关系:Logs / Metrics / Alarms
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart LR
subgraph Sources ["数据源"]
EC2["EC2 / ECS<br/>(CloudWatch Agent)"]
ALB["ALB / RDS<br/>(自动发指标)"]
App["应用代码<br/>(SDK 主动发)"]
end
Sources --> Logs["Logs<br/>(日志组 / 日志流)"]
Sources --> Metrics["Metrics<br/>(数值时序)"]
Logs -.->|"Logs Insights / EMF"| Metrics
Metrics --> Alarms["Alarms<br/>(阈值 + 评估周期)"]
Alarms --> SNS["SNS Topic"]
SNS --> Email["邮件"]
SNS --> Slack["Slack / Lambda"]
classDef src fill:#FEF3C7,stroke:#D97706,color:#92400E
classDef store fill:#3B82F6,stroke:#2563EB,color:#fff
classDef alarm fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D
classDef out fill:#10B981,stroke:#059669,color:#fff
class EC2,ALB,App src
class Logs,Metrics store
class Alarms alarm
class SNS,Email,Slack out简短解释:
- Logs 存非结构化或结构化日志,可全文搜索 / SQL 风格查询
- Metrics 存数值时序,自动按 1 分钟 / 5 分钟聚合
- Alarms 监听 Metrics(或 Metrics 数学组合),命中阈值发送 SNS 通知
10.2 日志层级:Log Group → Log Stream → Log Event
CloudWatch Logs 三级层级:
- Log Group(日志组):通常按应用/服务划分,如
/aws/ec2/my-app、/aws/lambda/payment-fn - Log Stream(日志流):组内更细的分组,通常按实例 ID 或 hostname
- Log Event(日志事件):具体一条日志
订阅过滤器(Subscription Filter):把匹配 pattern 的日志实时转出到 Lambda、Kinesis Data Stream 或 Firehose,实现日志告警、流式处理、转存到 S3。
10.3 Logs Insights:5 个常用查询模板
Logs Insights 用类 SQL 语法查日志,覆盖 90% 排查场景。5 个常用模板:
1 | -- 1. 错误统计(每 5 分钟一个 bucket) |
@timestamp @message 是 CloudWatch 自动注入的字段;其它字段需要日志本身是 JSON 结构化(CloudWatch 自动解析顶层字段)。
10.4 EMF:从结构化日志直出指标
EMF(Embedded Metric Format,嵌入式指标格式)= 在结构化 JSON 日志里嵌入元数据。CloudWatch 自动从日志抽出对应数值生成 Metrics,省掉一次 PutMetricData API 调用,对高频指标场景大幅降本。
示例(应用打一条 EMF 日志):
1 | { |
写到 CloudWatch Logs 后,CloudWatch 自动按 MyApp/Latency、MyApp/RequestCount 生成指标,按 Service、Endpoint 维度可分组查询。收益:每秒 1000 次请求场景,传统方式调 PutMetricData 每月 $30+;改 EMF 仅算日志摄取费 + 0 调用费。
10.5 告警链路:Metric → Alarm → SNS → 邮件/Slack
完整告警链路示例:监控 ALB 5xx 数量超阈值发邮件。
1 | # Step 1 创建 SNS Topic |
告警三要素:metric(指标)、period × evaluation-periods(评估窗口)、threshold(阈值)。Slack 通知通过 SNS → Lambda → Slack Webhook 实现,Lambda 函数用官方模板 1 小时搞定。
💰 CloudWatch:Logs 摄取 $0.50/GB、存储 $0.03/GB- 月;自定义指标前 10,000 个 $0.30/月每个,10,001-250,000 $0.10/月每个;标准告警 $0.10/告警 - 月;Logs Insights 查询按扫描数据计费。这些是页面 example 措辞,未明示 us-west-2,请以 AWS Pricing Calculator 为准。
来源:AWS CloudWatch Pricing
💡 进阶 / 成本:CloudWatch Logs 默认保留期是 “Never Expire”——不改的话日志永久存,几个月后存储费可能比摄取费还贵。省钱优先级:(1) 每个 Log Group 都设保留期,按 RPO 选 30 天 / 90 天 / 1 年;(2) 高频低价值日志(健康检查、心跳)改 sample 或本地丢弃;(3) 用 Subscription Filter 转出冷数据到 S3,原 Log Group 设短保留。这 3 步通常能砍掉 50%+ 日志账单。
10.6 常见踩坑
PutMetricData 高频调用账单暴涨
- 现象:自定义指标账单从每月几十美元飙到几百
- 根因:应用每次请求都调 PutMetricData,单价 $0.01/1000 次看似便宜,但 QPS 高时积少成多;且每个 dimension 组合算一个独立 Metric,high cardinality(如 user_id 当 dimension)一夜千万 metric
- 处理:换 EMF(10.4 节);或客户端聚合(每分钟一次 PutMetricData);dimension 值的基数严格控制 < 1000
告警评估周期过短,瞬时尖峰频繁触发
- 现象:CPU 偶尔瞬时尖到 90% 就发告警,运维被噪声淹没
- 根因:Alarm 设了
period 60s, evaluation-periods 1,1 分钟超阈值就触发 - 处理:改
period 300s, evaluation-periods 2(连续 10 分钟超阈值才报),或用datapoints-to-alarm 3 of 5(5 个评估周期里有 3 次超阈值才报)
日志 Subscription Filter 触发 Lambda 死循环
- 现象:Lambda 调用次数异常飙升,账单激增
- 根因:Lambda 自身的日志写到 CloudWatch Logs,又被同一个 Filter 命中触发自己——形成自循环
- 处理:Subscription Filter 的 Log Group 排除掉 Lambda 自己的 Log Group(如
/aws/lambda/my-fn);或在 Lambda 代码里检测到来自自己的日志直接返回
10 章的概念铺完了,接下来把它们串成一个真能跑的最小生产架构——30 分钟从零搭出来。
11. 实战配方:30 分钟搭建生产可用 Web 服务
本章独立可读:把前 10 章的概念串成一个能跑起来的最小生产架构。读完跟着做完,你就有了一个跨 AZ 高可用、HTTPS 域名访问、可弹性伸缩、有告警的 Web 服务。
11.0 前置与目标
必备前置:
- AWS 账户已开通,账单告警已配置(实验欠费风险来自 NAT GW、RDS、ALB 长开机器)
- 本机已
aws configure,当前 IAM 凭证拥有 EC2 / VPC / RDS / ELB / Auto Scaling / CloudWatch / Route 53 / ACM 完整权限 - 一个已托管在 Route 53 的域名(或可手动加 CNAME 到第三方 DNS 的域名)
- 本文统一基准 Region:us-west-2
目标架构:
%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#3B82F6'}}}%%
flowchart TB
User["用户浏览器"]
R53["Route 53<br/>app.example.com"]
ACM["ACM 证书<br/>(us-west-2)"]
subgraph VPC ["VPC 10.0.0.0/16 — us-west-2"]
subgraph PubA ["公有子网 us-west-2a (10.0.1.0/24)"]
ALBnodeA["ALB 节点 A"]
NATa["NAT GW"]
end
subgraph PubB ["公有子网 us-west-2b (10.0.3.0/24)"]
ALBnodeB["ALB 节点 B"]
end
subgraph PriA ["私有子网 us-west-2a (10.0.2.0/24)"]
EC2a["EC2 (ASG)"]
end
subgraph PriB ["私有子网 us-west-2b (10.0.4.0/24)"]
EC2b["EC2 (ASG)"]
end
subgraph IsoA ["隔离子网 us-west-2a (10.0.5.0/24)"]
RDSa["RDS Primary"]
end
subgraph IsoB ["隔离子网 us-west-2b (10.0.6.0/24)"]
RDSb["RDS Standby"]
end
end
User -->|"DNS 解析"| R53
User -->|"HTTPS"| ALBnodeA
User -->|"HTTPS"| ALBnodeB
ALBnodeA --> EC2a
ALBnodeB --> EC2b
EC2a -.->|"读写"| RDSa
EC2b -.->|"读写"| RDSa
RDSa -.->|"同步"| RDSb
EC2a --> NATa
classDef pub fill:#DBEAFE,stroke:#2563EB
classDef pri fill:#FEF3C7,stroke:#D97706
classDef iso fill:#FEE2E2,stroke:#DC2626
classDef ext fill:#10B981,stroke:#059669,color:#fff
class PubA,PubB,ALBnodeA,ALBnodeB,NATa pub
class PriA,PriB,EC2a,EC2b pri
class IsoA,IsoB,RDSa,RDSb iso
class User,R53,ACM ext最终成品:跨 2 AZ 高可用(任一 AZ 故障不影响服务);HTTPS 域名访问;ASG 弹性伸缩 min=2, max=4;RDS Multi-AZ 自动故障切换;CloudWatch 三个关键告警(5xx / CPU / DB 连接数);月成本约 $200-300(不含域名注册)。
架构思路一句话:流量从 Route 53 进 ALB,ALB 跨 AZ 把请求分到私有子网里的 EC2 集群,EC2 读写隔离子网里的 RDS Multi-AZ。三层各自独立 SG,数据库不暴露任何公网入口。下面 8 步把这套搭起来。
11.1 步骤 1:VPC + 双 AZ 子网(5 分钟)
为什么要分公有 / 私有 / 隔离三种子网?公有(Public)放需要被公网直连的组件——ALB 节点、NAT GW;私有(Private)放走 NAT 出网但不被公网直连的应用——EC2;隔离(Isolated)连 NAT 都没有,只接受私有子网内部流量——RDS。流量入站走 IGW → ALB → EC2,出站(如装包、调外部 API)走 NAT GW;数据库整层断网。
1 | VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --region us-west-2 --query 'Vpc.VpcId' --output text) |
⚠️ 完整 CLI 涉及路由表创建、关联、NAT GW + Elastic IP,命令较长。生产环境强烈建议用 Terraform / CloudFormation 管。本节给关键骨架,详见 AWS VPC 官方教程。NAT GW 一台每月固定 $32 + 流量费,是这套架构里仅次于 RDS 的固定成本头号——做实验就建一台跨 AZ 共用,正式生产再考虑每 AZ 一台规避 NAT 单点。
11.2 步骤 2:三件套安全组(3 分钟)
链式引用:Internet:443 → sg-alb → sg-ec2:80 → sg-rds:3306。每一层只放上一层的 SG 作 source,不写 CIDR。
1 | # ALB SG:接公网 443(80 用于 80→443 重定向) |
关键:链式 SG 引用(sg-alb → sg-ec2 → sg-rds)让流量路径单向受控——任何外部 IP 都无法直连 EC2 或 RDS,只能从 ALB 进。这里不要写 CIDR 当 source(如 --cidr 10.0.0.0/16),那样整个 VPC 内任何资源都能连 EC2,等于把内部边界拆了;引用 SG ID 才是真正的 “ 白名单 “。新手最常见的错配是给 sg-rds 开 --cidr 0.0.0.0/0:3306——配合公网子网就是把数据库直接挂到公网上,几小时就被扫到。
11.3 步骤 3:RDS Multi-AZ MySQL(8 分钟)
Multi-AZ 在另一 AZ 起一台同步副本(Standby),不对外提供读流量,只用作故障切换。主库挂了或被 AZ 级故障带走时,RDS 在 60-120 秒内把 DNS 端点切到副本,应用代码不用改。这是最便宜可靠的「数据库高可用」方案。读副本(Read Replica)是另一回事,本配方不用。
1 | # DB Subnet Group 用两个隔离子网 |
11.4 步骤 4:Launch Template + user-data(5 分钟)
1 | cat > /tmp/user-data.sh <<'EOF' |
注意:HttpTokens=required 强制 IMDSv2,把 SSRF 取凭证的链路断掉(参见 4.3 节背景)。HttpPutResponseHopLimit=1 防止容器内进程多跳一次拿到元数据;如果你打算在这台 EC2 上跑 Docker / ECS Agent,按官方文档设为 2。user-data 在首次启动自动执行,把 nginx 装好——配合 ASG 弹性伸缩时,新机器从无到有上线只要 30-60 秒。
11.5 步骤 5:Auto Scaling Group(2 分钟)
1 | aws autoscaling create-auto-scaling-group \ |
health-check-type ELB 让 ASG 用 ALB 的 7 层健康检查替代默认的 EC2 状态检查——应用挂了但实例还活着的 “ 僵尸 “ 也会被踢出并替换。grace-period 300 给 user-data 留 5 分钟跑装包脚本,否则新实例还没起 nginx 就被判定不健康,循环 terminate / launch 烧钱。vpc-zone-identifier 必须填两个 AZ 的私有子网——只填一个 AZ 时,那个 AZ 一挂全部容量归零,Multi-AZ RDS 也救不了。
11.6 步骤 6:ALB + Target Group + HTTPS(5 分钟)
ALB 与 EC2 之间用 HTTP 80 而不是 HTTPS。TLS 在 ALB 终结,证书只装一份;EC2 上跑普通 nginx 就行(VPC 内流量走 AWS 骨干网,不存在中间人风险)。ALB 与公网之间一律 HTTPS,并把 80 端口做 301 重定向到 443——避免用户敲 http:// 时拿到不安全连接。
1 | TG_ARN=$(aws elbv2 create-target-group --name demo-tg --protocol HTTP --port 80 --vpc-id $VPC_ID \ |
11.7 步骤 7:Route 53 域名 + ACM 证书(2 分钟)
ACM(AWS Certificate Manager,证书管理器)签发的证书只能给同 Region 的 AWS 服务用——给 us-west-2 的 ALB 装证书,证书就必须在 us-west-2 申请。例外是 CloudFront:它要求证书在 us-east-1。本配方不涉及 CloudFront,所以同 Region 申就对了。
1 | # ACM 证书必须与 ALB 同 Region |
11.8 步骤 8:CloudWatch 告警(3 分钟)
告警不是越多越好,越多越容易被忽略。最小可用告警三条线打底:
- 入口异常:5xx 突增——用户已经看到错误页
- 容量异常:CPU 持续高位——准备扩容或排查热点
- 依赖异常:DB 连接数飙高——通常是连接池泄漏或慢查询堵塞
任何一条响,就值得人去看。
1 | TOPIC_ARN=$(aws sns create-topic --name demo-alarms --region us-west-2 --query 'TopicArn' --output text) |
11.9 验证清单
部署完成「看着都对」不等于真的可用。下面 5 项是最低验证集,专门把架构里「高可用」和「可观测」两个承诺打一遍。不打就只是一堆资源,不是生产服务。逐项确认(任一不通就回到对应步骤排查):
- 浏览器访问
https://app.example.com返回 200,证书绿锁 - [控制台手动 terminate 一台 ASG 实例,2-3 分钟内 ASG 自动起新实例补齐
- RDS 控制台触发 “Reboot with failover”,应用短暂报错(约 60-120 秒)后恢复
aws sns publish --topic-arn $TOPIC_ARN --message test,邮箱能收到(确认订阅已生效)- CloudWatch Logs 控制台能看到应用日志流(如配了 CloudWatch Agent)
11.10 销毁脚本(避免账单意外)
⚠️ 本节最重要:实验做完一定要销毁。NAT GW + RDS Multi-AZ + ALB 三件套不停就是每天 $5-10 的烧。
按依赖反向顺序销毁(销毁前再确认一次资源名 / VPC ID):
1 | # 1. CloudWatch + SNS |
💡 进阶 / IaC:手动脚本一长就出错。生产配方建议用 Terraform / CloudFormation / CDK 管理整套资源——一份代码起一份环境,
terraform destroy一键回收,比delete-*命令链条稳得多。本章配方的全部资源用 Terraform 写出来约 200 行,作为下一步练习刚好。
正文结束。最后附上 CLI 速查表和延伸阅读,留作日常翻阅。
12. 附录
本附录提供两块内容:常用 CLI 速查(按服务分组)和推荐进阶阅读。
12.1 常用 CLI 速查
所有命令前置:已配置 awscli + IAM 权限 + 默认 Region us-west-2。
EC2
1 | # 列出运行中实例(ID + AZ + 私网 IP) |
S3
1 | # 列桶 |
RDS
1 | # 列实例(ID + endpoint + 端口 + master 用户) |
CloudWatch
1 | # 列告警当前状态 |
ELB
1 | # 列 Load Balancer |
IAM / Secrets Manager
1 | # 看当前调用方身份 |
12.2 推荐进阶阅读
- AWS Well-Architected Framework(六大支柱:卓越运营 / 安全 / 可靠性 / 性能 / 成本 / 可持续):官方门户
- AWS 价格计算器:calculator.aws — 任何价格疑问的第一站
- AWS 公开定价 API(机器可读 JSON,文件较大但是最权威的源):
https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/<service>/current/<region>/index.json - AWS 中国官网博客:aws.amazon.com/cn/blogs/china/ — 中文实战案例
12.3 价格声明
文中价格抓取自 AWS 官方页(基准 Region us-west-2,抓取日期 2026-04-26),每张价格卡片带「来源」链接。价格随时调整,生产决策请以 AWS Pricing Calculator 实时查询为准。