Appearance
第 13 讲|常见技术栈
打开任意一个稍复杂的 Web 系统架构图,会看到一组组件名:Vue、React、FastAPI、Spring Boot、MySQL、Redis、Kafka、Nginx、Prometheus、Grafana……第一次接触很容易眼花。
这些组件不是平铺在一起的工具清单,而是各自占据系统的某一层:页面、接口、数据、入口、发布、观测。理解技术栈的关键是先看每个组件在系统里站哪一层——页面谁渲染、接口谁提供、数据放哪、异步任务怎么跑、外部请求从哪进、出问题去哪看。把这些位置关系理清,后面接触任何新组件都能快速归类。
本讲按系统的层次结构,梳理每一层的主流技术选择、适用场景、选型考量。
一、按层次理解技术栈
一个典型 Web 系统的完整技术栈分层:

接下来逐层讲清楚每一层的主流选择。
二、页面层(前端)
前端负责浏览器内的页面结构、样式、交互、调用后端接口。最终在浏览器中加载的就是 HTML、CSS、JavaScript、图片、字体。
主流技术分类
| 类型 | 主流选择 | 在系统中的位置 |
|---|---|---|
| 基础能力 | HTML、CSS、JavaScript | 浏览器原生支持,所有前端最终跑这三样 |
| 框架 | Vue、React、Angular | 组件化开发、状态管理、路由 |
| 构建工具 | Vite、Webpack、esbuild | 把 Vue/JSX/TS 编译为浏览器可执行的 JS |
| UI 组件库 | Element Plus、Ant Design、Naive UI、Tailwind | 现成的表单、表格、弹窗、布局 |
| 状态管理 | Pinia、Redux、Zustand | 跨组件共享状态 |
| 路由 | Vue Router、React Router | SPA 内部页面跳转 |
框架选择的现状
| 框架 | 国内 | 海外 / 国际 |
|---|---|---|
| Vue | 国内主流(简洁、文档好、上手快) | 较少使用 |
| React | 大厂主流(生态最庞大、招聘多) | 全球主流 |
| Angular | 较少 | 企业级项目较多 |
| Svelte / Solid | 新兴,较少 | 新兴,增长快 |
技术框架选择的现实考量:团队熟悉度 > 招聘市场 > 技术本身。各主流框架在能力上没有质的差距,Vue/React 都能胜任绝大多数业务,选哪个更多看团队基础。
何时不需要前端框架
简单场景下,原生 HTML/CSS/JS 完全够用,不必上框架:
- 静态展示页面
- 简单表单
- 内部小工具
- 静态文档站
引入 Vue/React 会增加构建复杂度、学习成本、首屏加载体积。框架是为复杂交互而设计的,不是为了"显得现代化"。
前后端的连接点:HTTP API
前端代码通过 fetch、axios 调用后端 API:
javascript
fetch('/api/users/me', {
headers: { 'Authorization': `Bearer ${token}` }
})
.then(res => res.json())
.then(user => renderProfile(user));后端返回 JSON,前端拿到后渲染页面。这就是前后端分离的核心交互模式。
前端的发布
前端构建后产出的静态文件(HTML / CSS / JS / 图片),可以部署在:
- CDN:全球加速,主流选择
- 对象存储 + CDN:OSS/S3 作为源站,CDN 缓存分发
- Nginx:简单场景,适合内部系统
- 边缘平台:Cloudflare Pages、Vercel、Netlify
三、接口层(后端)
后端负责HTTP 接口、业务逻辑、认证权限、数据库读写、调用外部系统。
主流语言与框架
| 语言 | 主流框架 | 适用场景 |
|---|---|---|
| Java | Spring Boot、Spring Cloud、Quarkus | 国内大厂核心业务、企业级微服务 |
| Python | FastAPI、Django、Flask | 运维平台、内部工具、数据处理、AI 应用 |
| Go | Gin、Echo、Fiber、net/http | 云原生组件、API 网关、高并发服务 |
| Node.js | Express、NestJS、Koa、Fastify | BFF、轻量 API、与前端 JS 同栈 |
| .NET | ASP.NET Core | Windows 生态、企业系统 |
| Rust | Actix、Axum | 极致性能、新兴选择 |
| Ruby | Rails | 国外创业公司、快速原型 |
| PHP | Laravel、Symfony | 传统 Web、内容管理系统 |
各语言的适用边界
- Java — 生态最完整,招人最容易,大厂核心业务首选。劣势:启动慢、内存占用高、入门曲线陡
- Python — 开发快、可读性好,数据处理与 AI 生态独一无二。劣势:运行性能中等
- Go — 编译为单个二进制,部署极简,适合云原生(K8s、Docker、Prometheus 全家桶都是 Go)。劣势:错误处理冗长、泛型较新
- Node.js — 与前端 JS 同语言,前端团队能顺手做后端。劣势:CPU 密集型不擅长
- Rust — 性能与安全极致,新兴增长。劣势:学习曲线陡
语言选择的决定性因素是团队基础,不是语言本身的"优劣"。
后端不只是几个路由函数
新手容易以为"后端就是写几个路由 + SQL"。真实生产级后端要处理的非业务代码往往比业务代码还多:
| 模块 | 作用 |
|---|---|
| 配置管理 | 多环境、热更新、敏感信息加密 |
| 数据库连接池 | 连接复用、健康检查、连接数控制 |
| HTTP 客户端 | 超时、重试、连接池、TLS |
| 统一错误处理 | 异常 → 标准响应格式 |
| 中间件 | 认证、限流、日志、CORS |
| 优雅关闭 | 收到信号后处理完已有请求再退出 |
| 健康检查 | Liveness / Readiness |
| Metrics 暴露 | /metrics 端点 |
| 日志规范 | 结构化日志、Trace ID 透传 |
| 链路追踪 | OpenTelemetry SDK 集成 |
| 配置中心客户端 | 动态拉取配置 |
| 服务注册客户端 | 启动时注册、停止时注销 |
成熟的框架(Spring Boot、FastAPI、Gin)会把大部分基础设施做成开箱即用,但理解每一块在做什么,才能真正排查问题。
四、数据层
数据库保存系统的所有状态——用户、订单、权限、审计、配置、任务记录,所有"持久数据"都要落到某种存储。

按数据特性选存储类型
| 类型 | 主流选择 | 适合存什么 |
|---|---|---|
| 关系型数据库 | MySQL、PostgreSQL、Oracle | 用户、订单、权限、审计、配置等结构化数据 |
| 文档数据库 | MongoDB、CouchDB | 字段变化多、嵌套结构、文档型数据 |
| 缓存/键值 | Redis、Memcached | 热点数据、会话、计数器、分布式锁 |
| 列式数据库 | ClickHouse、Cassandra | 大数据分析、时序聚合 |
| 搜索引擎 | Elasticsearch、OpenSearch | 全文检索、日志检索 |
| 时序数据库 | InfluxDB、TimescaleDB、Prometheus | 监控指标、IoT |
| 图数据库 | Neo4j、JanusGraph | 社交关系、推荐 |
| 向量数据库 | Milvus、Qdrant、pgvector | AI/向量检索 |
MySQL vs PostgreSQL
国内传统业务系统 MySQL 用得最多——稳定、生态成熟、运维资料多。PostgreSQL 在以下场景上比 MySQL 强:
- 复杂 SQL(CTE、窗口函数、递归查询)
- JSON/JSONB 字段(原生支持索引和查询)
- GIS 地理数据(PostGIS 扩展)
- 全文检索(原生支持)
- 扩展能力(自定义类型、函数、操作符)
新项目选型时,PostgreSQL 是越来越被推荐的选择——除非有特别原因(MySQL 团队经验深、强依赖某 MySQL 特性)。
多数据库共存:是常态
业务系统同时使用多种数据库是常态:
MySQL/PostgreSQL → 核心业务数据(用户、订单、权限)
Redis → 缓存、会话、限流、锁
Elasticsearch → 全文搜索、日志检索
ClickHouse → 数据分析、报表
MongoDB → 内容型数据、配置
S3/OSS → 文件、备份不同数据各回各家,每种存储用在它最擅长的场景。
数据库选型的真实考量
数据库选型不只看"能不能存",还要看:
- 运维生态:监控、备份恢复、迁移工具是否成熟
- 团队熟悉度:运维难度,故障时谁能修
- 索引能力:能否覆盖业务的查询模式
- 权限模型:是否能满足合规要求
- 社区活跃度:遇到问题能找到答案
- 云厂商托管:是否有 RDS 形式的托管服务
一个团队没人能运维的数据库,再先进也不能上生产——出问题时无人能修,损失可能比不上的"先进性"大得多。
五、缓存与消息队列

缓存
缓存放在数据库前面,挡住重复查询。Redis 是最主流的选择——除了缓存,经常顺手承担:
- 会话存储(Session)
- 限流计数器
- 分布式锁
- 排行榜(zset)
- 实时排重(set)
- 简单队列(list / stream)
一个 Redis 实例能解决一组小问题,所以几乎所有 Web 系统的技术栈里都有 Redis。
消息队列
消息队列放在服务之间,主要解决两个问题:
| 场景 | 价值 |
|---|---|
| 异步执行 | 用户请求不用等待耗时操作完成 |
| 削峰填谷 | 突发流量被缓冲,后端按自己节奏消费 |
| 解耦 | 生产者和消费者互不感知,可独立扩展 |
| 广播 | 一条消息多个下游消费 |
主流消息队列
| 消息系统 | 特点 | 适用场景 |
|---|---|---|
| RabbitMQ | AMQP 协议,功能丰富,可靠投递 | 任务分发、传统业务队列 |
| Kafka | 高吞吐、日志型设计、分区有序 | 日志流、事件流、数据管道 |
| RocketMQ | 阿里出品,事务消息、延迟消息 | 国内电商、金融业务 |
| Pulsar | 计算存储分离 | 新兴选择,云原生 |
| Redis Stream/List | 轻量,与 Redis 共用 | 内部小任务,不想新增组件 |
| NATS | 轻量、低延迟 | 微服务通信、IoT |
异步处理的标准模式
典型场景:用户点击"导出报表"
同步方案的问题:接口同步等待生成,可能需要数十秒到数分钟,用户体验差,超时风险高。
异步方案:
1. 用户请求导出 → 接口立即返回任务 ID
2. 生成任务推入消息队列
3. 后台 worker 消费队列,真正生成报表
4. 生成完毕,更新任务状态,通知用户
5. 用户通过任务 ID 查询状态、下载结果关键认知:"请求已接收"(接口成功)≠ "任务已完成"(报表已生成)。
排查这类问题时,要看:
- 任务状态机:任务当前处于什么状态
- 队列积压:有没有消息没被消费
- 消费失败:重试次数、失败原因
- 消费者实例:是否在运行、有没有崩溃
六、文件存储
上传的文件(头像、附件、图片)、备份包、日志归档、构建产物——这些不适合长期绑在某台应用服务器的本地目录上。
对象存储:主流方案
按 bucket(桶)和 object key(对象键)组织文件,通过 HTTP API 访问。主流选择:
| 方案 | 类型 |
|---|---|
| AWS S3 | 云厂商(行业标准) |
| 阿里云 OSS | 云厂商 |
| 腾讯云 COS | 云厂商 |
| MinIO | 自建,兼容 S3 API |
| Ceph RGW | 自建,大规模 |
文件元数据与对象解耦
后端数据库里只保存文件元数据,不直接存文件本身:
| 字段 | 含义 |
|---|---|
file_name | 用户看到的原始文件名 |
size | 文件大小 |
mime_type | MIME 类型 |
owner_id | 归属用户/对象 |
object_key | 对象存储中的真实路径 |
upload_time | 上传时间 |
etag | 文件指纹,校验完整性 |
数据库存元数据,对象存储存实际文件,各自负责擅长的部分。
为什么不能放本地目录
应用扩为多实例时本地存储立即失效:
- 用户上传头像到
app-01,文件保存在app-01:/data/uploads/ - 下次访问头像,请求被分到
app-02 app-02本地没有这个文件 → 404
对象存储让多个实例访问同一份文件,根本解决这个问题。同时:
- 对象存储自身有副本和容灾,可靠性高
- 与应用实例解耦,实例随时可重建
- 公网访问可直接走 CDN,加速分发
七、入口层
入口层负责接收外部请求,转发到正确的内部服务。这一层组件较多,各司其职。
入口层组件
| 组件 | 主要职责 |
|---|---|
| CDN | 静态资源全球分发、缓存、抗 DDoS |
| WAF | 安全过滤(SQL 注入、XSS、爬虫) |
| 云负载均衡(SLB/ALB) | 公网入口、四层/七层转发 |
| Nginx | 反向代理、TLS 终止、限流、静态资源 |
| HAProxy | 高性能负载均衡(四层/七层) |
| Ingress | K8s 集群 HTTP/HTTPS 入口 |
| API 网关(Kong/APISIX/Higress) | 认证、路由、限流、协议转换、API 管理 |
完整入口链路
用户 → DNS → CDN → WAF → 云 LB → Ingress/Nginx → 后端服务每一层都可能成为问题源,出现 502、504、403、证书错误时,入口层是第一处检查点。
入口日志能看到:请求是否进入、转发到哪个后端、后端返回状态、耗时分布。80% 的"用户访问异常"问题,从入口日志开始查最快。
API 网关 vs Nginx
| 维度 | Nginx | API 网关(Kong/APISIX) |
|---|---|---|
| 主要用途 | 反向代理 + 静态资源 | API 管理 + 服务路由 |
| 配置方式 | 配置文件 | 控制台 / API |
| 插件能力 | 较少(需要 Lua) | 丰富(认证、限流、转换、日志等几十种) |
| 动态路由 | 不支持热更新(reload 切换) | 实时更新 |
| 服务发现集成 | 较少 | 原生支持 |
| 适用场景 | 简单代理、静态资源 | 微服务 API 管理 |
简单场景用 Nginx 足够;微服务架构、API 管理需求复杂的场景才需要 API 网关。
八、可观测与发布
可观测组件
可观测组件负责"看见"系统状态,出问题时能定位:
| 能力 | 主流选择 |
|---|---|
| 指标采集和存储 | Prometheus、VictoriaMetrics、Mimir |
| 指标看板 | Grafana(几乎是标准) |
| 告警 | Alertmanager、Nightingale(夜莺) |
| 日志收集 | Filebeat、Fluentd、Promtail、Vector |
| 日志存储 / 查询 | Loki、Elasticsearch、OpenSearch、ClickHouse |
| 链路追踪 | OpenTelemetry、Jaeger、SkyWalking、Tempo |
| APM(应用性能管理) | SkyWalking、Datadog、New Relic |
发布组件
发布组件负责把代码变成线上版本:
| 能力 | 主流选择 |
|---|---|
| 代码仓库 | GitLab、GitHub、Gitea、Bitbucket |
| CI(持续集成) | GitLab CI、Jenkins、GitHub Actions、Drone、Tekton |
| 镜像仓库 | Harbor、阿里云 ACR、Docker Hub |
| CD / GitOps | Argo CD、Flux、Spinnaker |
| 配置管理 | Ansible、Terraform、Pulumi |
九、一套典型的内部技术栈
把所有层串起来,一套典型的中型公司内部技术栈大概是:
前端 Vue 或 React + Vite + Element Plus / Ant Design
后端 Spring Boot(Java)或 FastAPI(Python)或 Gin(Go)
数据库 MySQL 或 PostgreSQL + Redis 缓存
搜索 Elasticsearch(可选)
文件 MinIO 或 云 OSS
消息 RabbitMQ 或 Kafka(可选)
入口 Nginx + 云 SLB
容器 Docker
编排 Kubernetes
监控 Prometheus + Grafana + Alertmanager
日志 Loki + Grafana,或 ELK
追踪 Jaeger 或 SkyWalking
CI/CD GitLab CI + Harbor + Argo CD
配置 Apollo 或 Nacos
注册中心 Nacos 或 Consul(微服务场景)这不是唯一答案,只是常见的位置关系。换其中任何一个组件(Vue → Svelte、MySQL → TiDB、Prometheus → VictoriaMetrics),只要功能定位相同,其他部分基本不需要变。
选型时的核心问题
接触任意新技术栈时,问自己这几个问题:
- 它解决什么问题? — 在系统的哪一层?
- 它替代什么? — 与已有组件的关系?
- 它的运维成本? — 谁能维护、出问题谁能修?
- 它的故障域? — 挂了影响范围多大?
- 它的退出成本? — 如果不合适,迁出去难不难?
能跑起来是一回事,出问题能排查、能演进、能替换是另一回事——后者才是技术选型的真正考验。
十、技术栈的演进规律
技术栈不是一成不变的——业务规模、团队能力、流量特点都在变化,技术栈也要跟着演进。常见演进路径:

启动期 单机部署 + 单数据库 + 简单 Web 框架
成长期 负载均衡 + 多实例 + Redis 缓存 + CDN
扩张期 数据库主从 + 消息队列 + 监控告警 + 日志聚合
成熟期 微服务 + K8s + 完整可观测 + CI/CD
大型化 服务网格 + 多机房 + 分库分表 + 流量治理每一步演进都要解决"业务真实痛点"——不要为了"看起来现代化"提前引入复杂度。Kubernetes 不是必需,微服务不是必需,服务网格更不是必需。架构演进的核心原则:业务驱动技术演进,而不是技术驱动架构升级。