8.9 KiB
8.9 KiB
技术选型框架
后端与全栈技术选型的结构化决策框架。防止分析瘫痪,同时确保严谨评估。
铁律:未经明确的取舍分析,不得做出任何技术选择。
"我喜欢"和"这很热门"都不是工程论证。
阶段一:先定需求,再选技术
非功能性需求(量化!)
| 维度 | 问题 | 糟糕的回答 | 好的回答 |
|---|---|---|---|
| 规模 | 多少并发用户? | "很多" | "1K 并发,500 RPS 峰值" |
| 延迟 | 可接受的 p99 响应时间? | "快" | "API < 200ms,报告 < 2s" |
| 可用性 | 需要的正常运行时间? | "永远在线" | "99.9%(年停机 8.7 小时)" |
| 数据量 | 预计存储增长? | "很多" | "100GB/年,1000 万行" |
| 一致性 | 强一致还是最终一致? | "一致" | "支付强一致,信息流最终一致" |
| 合规性 | 监管要求? | "有一些" | "GDPR 数据驻留欧盟,SOC 2 Type II" |
团队约束
- 团队规模与资深程度
- 团队已熟练掌握的技术
- 能否为此技术栈招到人?(查看招聘市场)
- 时间压力(几天还是几个月上线)
- 许可、基础设施、培训的预算
阶段二:评估矩阵
对每个选项按加权标准打分 1-5 分:
| 评估标准 | 权重 | 选项 A | 选项 B | 选项 C |
|---|---|---|---|---|
| 满足功能性需求 | 5× | _ | _ | _ |
| 满足非功能性需求 | 5× | _ | _ | _ |
| 团队经验 / 学习曲线 | 4× | _ | _ | _ |
| 生态成熟度(库、工具) | 3× | _ | _ | _ |
| 社区与长期 viability | 3× | _ | _ | _ |
| 运维复杂度 | 3× | _ | _ | _ |
| 招聘人才池 availability | 2× | _ | _ | _ |
| 成本(许可 + 基础设施 + 培训) | 2× | _ | _ | _ |
| 加权总分 | _ | _ | _ |
规则:
- 任何选项在 5× 标准上得 1 分 → 自动淘汰
- 选项间差距在 10% 以内 → 选团队最熟悉的
- 选项间差距在 15% 以内 → 进行有时间限制的概念验证(最长 2-5 天)
阶段三:决策树
后端语言 / 框架
什么类型的项目?
│
├─ REST/GraphQL API,快速开发
│ ├─ 团队熟悉 TypeScript → Node.js
│ │ ├─ 功能完备,企业级模式 → NestJS
│ │ ├─ 轻量灵活 → Fastify / Hono / Express
│ │ └─ 全栈 + React → Next.js API routes
│ ├─ 团队熟悉 Python
│ │ ├─ 高性能异步 API → FastAPI
│ │ ├─ 全栈,后台管理繁重 → Django
│ │ └─ 轻量级 → Flask / Litestar
│ └─ 团队熟悉 Java/Kotlin
│ ├─ 企业级,大型团队 → Spring Boot
│ └─ 轻量级,启动快 → Quarkus / Ktor
│
├─ 高并发,系统级
│ ├─ 微服务,网络编程 → Go
│ ├─ 极致性能,安全性 → Rust (Axum / Actix)
│ └─ 容错性 → Elixir (Phoenix)
│
├─ 实时(WebSocket、流式)
│ ├─ Node.js 生态 → Socket.io / ws
│ ├─ 可扩展的发布/订阅 → Elixir Phoenix
│ └─ 低延迟 → Go / Rust
│
└─ 机器学习 / 数据密集
└─ Python (FastAPI + ML libs)
数据库
什么数据模型?
│
├─ 结构化,关系型,ACID
│ ├─ 通用 → PostgreSQL ← 默认选择
│ ├─ 读密集,MySQL 生态 → MySQL / MariaDB
│ └─ 嵌入式 / 无服务器边缘 → SQLite / Turso / D1
│
├─ 半结构化,灵活 schema
│ ├─ 文档型 → MongoDB
│ ├─ 无服务器文档 → DynamoDB / Firestore
│ └─ 搜索密集 → Elasticsearch / OpenSearch
│
├─ 键值 / 缓存
│ ├─ 内存 + 数据结构 → Redis / Valkey
│ └─ 星球级 KV → DynamoDB / Cassandra
│
├─ 时间序列 → TimescaleDB / ClickHouse / InfluxDB
├─ 图 → Neo4j / Apache AGE (Postgres 扩展)
└─ 向量(AI 嵌入) → pgvector / Pinecone / Qdrant
默认: 从 PostgreSQL 开始。它能处理 80% 的使用场景。
缓存策略
| 模式 | 技术 | 何时使用 |
|---|---|---|
| 应用缓存 | Redis / Valkey | 会话、频繁读取、限流 |
| HTTP 缓存 | CDN (Cloudflare/Vercel) | 静态资源、公开 API 响应 |
| 查询缓存 | 物化视图 | 复杂聚合、仪表盘 |
| 进程内缓存 | LRU(内存) | 配置、小型查找表 |
| 边缘缓存 | Cloudflare KV / Vercel KV | 全球低延迟读取 |
消息队列 / 事件流
| 模式 | 技术 | 何时使用 |
|---|---|---|
| 任务队列(后台作业) | BullMQ / Celery / SQS | 邮件、导出、支付 |
| 事件流(回放、审计) | Kafka / Redpanda | 事件溯源、实时管道 |
| 轻量发布/订阅 | Redis Streams / NATS | 简单通知、广播 |
| 请求-回复(异步同步化) | NATS / RabbitMQ RPC | 内部服务调用 |
托管 / 部署
| 模式 | 技术 | 何时使用 |
|---|---|---|
| 无服务器(自动扩缩) | Vercel / Cloudflare Workers / Lambda | 流量波动、按量付费 |
| 容器(可预测) | Cloud Run / Render / Railway / Fly.io | 流量稳定、运维简单 |
| Kubernetes(大规模) | EKS / GKE / AKS | 10+ 服务、团队有 K8s 经验 |
| VPS(完全控制) | DigitalOcean / Hetzner / EC2 | 工作负载可预测、对成本敏感 |
阶段四:决策文档
ADR(架构决策记录)模板
# ADR-{NNN}: {标题}
## 状态:提议 | 已接受 | 已废弃 | 被 ADR-{NNN} 取代
## 背景
我们在解决什么问题?有哪些因素在起作用?
## 决策
我们选择了什么以及为什么?
## 评估
| 标准 | 权重 | 选中方案 | 备选方案 |
|-----------|--------|--------|-----------|
## 影响
- 正面:...
- 负面:...
- 风险:...
## 已拒绝的备选方案
- 选项 B:因...被拒绝
- 选项 C:因...被拒绝
常见技术栈模板
A:初创 / MVP(速度优先)
| 层 | 选择 | 理由 |
|---|---|---|
| 语言 | TypeScript | 前后端统一语言 |
| 框架 | Next.js(全栈)或 NestJS(API) | 快速迭代 |
| 数据库 | PostgreSQL (Supabase / Neon) | 托管服务,慷慨的免费额度 |
| 认证 | Better Auth / Clerk | 无需维护认证代码 |
| 缓存 | Redis (Upstash) | 对无服务器友好 |
| 托管 | Vercel / Railway | 零配置部署 |
B:SaaS / 商业应用(平衡)
| 层 | 选择 | 理由 |
|---|---|---|
| 语言 | TypeScript 或 Python | 团队偏好 |
| 框架 | NestJS 或 FastAPI | 结构化、可测试 |
| 数据库 | PostgreSQL | 可靠、功能丰富 |
| 队列 | BullMQ (Redis) | 简单的后台任务 |
| 认证 | OAuth 2.0 + JWT | 标准、灵活 |
| 托管 | AWS ECS / Cloud Run | 可扩缩容器 |
| 监控 | Datadog / Grafana + Prometheus | 完整可观测性 |
C:高性能(规模优先)
| 层 | 选择 | 理由 |
|---|---|---|
| 语言 | Go 或 Rust | 最大吞吐量、低延迟 |
| 数据库 | PostgreSQL + Redis + ClickHouse | OLTP + 缓存 + 分析 |
| 队列 | Kafka / Redpanda | 高吞吐量流处理 |
| 托管 | Kubernetes (EKS/GKE) | 细粒度扩缩 |
| 监控 | Prometheus + Grafana + Jaeger | 指标 + 追踪 |
D:AI / 机器学习应用
| 层 | 选择 | 理由 |
|---|---|---|
| 语言 | Python(API)+ TypeScript(前端) | 机器学习库 + 现代 UI |
| 框架 | FastAPI + Next.js | 异步 + SSR |
| 数据库 | PostgreSQL + pgvector | 关系型 + 嵌入 |
| 队列 | Celery + Redis | 机器学习任务处理 |
| 托管 | Modal / AWS GPU / Replicate | GPU 访问 |
反模式
| # | ❌ 不要做 | ✅ 应该做 |
|---|---|---|
| 1 | "X 在 HN 上火了" | 对照你自己的需求来评估 |
| 2 | 简历驱动开发 | 选团队能维护的 |
| 3 | "必须支持 100 万用户"(第一天) | 按当前需求的 10 倍构建,而非 1000 倍 |
| 4 | 评估好几周 | 限制在 3-5 天,然后做决定 |
| 5 | 不做决策文档 | 为每个重大选择写 ADR |
| 6 | 忽略运维成本 | 将部署、监控、调试成本纳入考量 |
| 7 | "以后重写" | 假设不会重写。慎重选择。 |
| 8 | 默认微服务 | 从单体开始,需要时再拆分 |
| 9 | 每个服务一个不同数据库(第一天) | 用一个数据库,有充分理由再拆分 |
| 10 | "谷歌就是这么做的" | 你不是谷歌。按你自己的场景来扩缩。 |
常见问题
问题 1:"团队无法就框架达成一致"
解决方法: 限制在 3 天内。填写评估矩阵。如果分数相差在 10% 以内,选多数人熟悉的。写入 ADR。继续推进。
问题 2:"我们选了 X,但它不合适"
解决方法: 检查沉没成本谬误。如果投入不到 2 周,立即切换。如果已超过 2 周,记录痛点并规划分阶段迁移。
问题 3:"我们需要微服务吗?"
解决方法: 几乎肯定不需要。从一个结构良好的单体开始。仅在以下情况才提取为服务:(a) 不同扩缩需求,(b) 不同团队所有权,(c) 不同部署节奏。