关键决策回顾

那些让我纠结到凌晨三点的选择

回头看”光影”的 6 个月开发历程,技术方案的选型并不是一路顺风的。很多决策当时纠结了很久——甚至有几个选择,我后来发现并非最优解。

这一章,我想诚实地回顾每一个关键决策:当时考虑了什么、放弃了什么、结果如何。

决策 1:为什么先审后处理?

背景:用户上传一张图片后,是先审核内容再生成缩略图,还是先生成缩略图再审核?

方案 A:先审后处理(最终选择)
用户上传 → 审核 → 通过 → 生成缩略图 → 可见

方案 B:先处理后审核
用户上传 → 生成缩略图 → 审核 → 通过后可见

方案 C:边审边处理
用户上传 → 审核 + 处理并行 → 汇合 → 可见

但这个决策有一个副作用:用户上传后需要等审核完成(200ms1s)再等处理完成(13s),总共 2~4 秒才能看到图片。我通过在审核通过后立即返回”上传成功”、后台异步处理缩略图来缓解这个问题。

决策 2:为什么客户端直传 OSS?

背景:图片上传可以走服务器中转,也可以让客户端直接传到 OSS。

方案 A:客户端直传 OSS(最终选择)
客户端 → OSS(通过 STS 临时凭证)

方案 B:服务器中转
客户端 → 应用服务器 → OSS

方案 C:服务器中转 + 流式转发
客户端 → 应用服务器(流式转发)→ OSS

直传的风险:用户可能绕过审核,直接访问 OSS 上的原图。我通过以下措施防护:

决策 3:为什么选 WebP 作为主力格式?

背景:现代图片格式有 WebP 和 AVIF 两种选择。

方案 A:WebP 为主 + AVIF 辅助(最终选择)
方案 B:AVIF 为主 + WebP 兜底
方案 C:只用 WebP
方案 D:只用 JPEG(不转码)

前端实现:

事后评估:这个决策基本正确,但有一个遗憾——AVIF 的编码速度确实太慢。如果当时选择”AVIF 异步生成 + WebP 同步返回”,用户体验会更好。

决策 4:为什么用消息队列而不是直接调用?

背景:审核和处理是异步流程,可以用消息队列解耦,也可以直接在代码里调用。

方案 A:消息队列(RabbitMQ)(最终选择)
上传服务 → RabbitMQ → 审核服务 → RabbitMQ → 处理服务

方案 B:直接 HTTP 调用
上传服务 → HTTP 调用审核服务 → HTTP 调用处理服务

方案 C:数据库轮询
上传服务写入数据库 → 审核服务轮询数据库 → 处理服务轮询数据库

队列配置细节

决策 5:为什么用 CDN 边缘裁剪而不是预生成所有尺寸?

背景:缩略图可以预先全部生成,也可以在 CDN 边缘实时裁剪。

方案 A:预生成固定尺寸 + CDN 边缘裁剪兜底(最终选择)
方案 B:完全预生成所有尺寸
方案 C:完全依赖 CDN 边缘裁剪

决策 6:为什么文件命名用日期+哈希而不是自增 ID?

背景:图片存储路径可以有多种命名方式。

方案 A:日期 + 哈希(最终选择)
originals/2024/06/a3/d4e5f6...jpg

方案 B:自增 ID
originals/00001.jpg, originals/00002.jpg, ...

方案 C:用户 ID + 时间戳
originals/user_123/1717286400.jpg

方案 D:UUID
originals/550e8400-e29b-41d4-a716-446655440000.jpg

所有决策一览

┌───────────────────┬──────────────────────┬────────────────────────────────┐
│     决策问题      │       最终选择       │          核心理由              │
├───────────────────┼──────────────────────┼────────────────────────────────┤
│ 审核/处理顺序     │ 先审后处理           │ 省处理资源,防违规进 CDN       │
│ 上传链路          │ 客户端直传 OSS       │ 省带宽,快,支持分片           │
│ 图片格式          │ WebP 主力 + AVIF 辅助│ 97% 支持率 + 渐进增强          │
│ 异步通信          │ RabbitMQ 消息队列    │ 解耦,缓冲,可扩展            │
│ 缩略图策略        │ 预生成 + 边缘裁剪    │ 95% 场景预生成,5% 边缘兜底   │
│ 文件命名          │ 日期 + 内容哈希      │ 可管理 + 无热点 + 可去重      │
│ CDN 选型          │ 阿里云 CDN           │ 国内节点多,与 OSS 同厂商     │
│ 存储方案          │ 阿里云 OSS           │ 无需运维,按需付费            │
│ 监控方案          │ Prometheus+Grafana   │ 开源免费,生态丰富            │
│ 数据库            │ PostgreSQL           │ JSON 支持好,事务可靠         │
└───────────────────┴──────────────────────┴────────────────────────────────┘

决策模式总结

回看这些决策,我发现了三个模式:

那些”如果重来”的决策

不是所有决策都是最优的。诚实地记录那些我后悔的选择: