语言选型不能只比较语法。Web 服务真正的差异在于请求由谁接收、用什么并发模型执行、状态保存在何处,以及过载时怎样表现。
四条简化链路
1 | PHP:Nginx -> FastCGI -> FPM Worker -> 框架入口 |
这些是常见模型,不是不可改变的规则。例如 Java 也有响应式和虚拟线程方案,PHP 也可以使用常驻进程框架。
核心比较
| 维度 | PHP-FPM | Go | Java/Spring | Node.js |
|---|---|---|---|---|
| 常见并发单元 | Worker 进程 | Goroutine | 平台线程或虚拟线程 | 事件循环任务 |
| 请求状态 | 通常请求级 | 进程内共享需同步 | 堆对象共享需同步 | 单线程 JS 状态也会发生逻辑竞态 |
| I/O 模型 | Worker 同步等待常见 | 阻塞写法由 Runtime 调度 | 线程池同步模型常见 | 异步 I/O |
| 启动与部署 | 简单成熟 | 单文件部署方便 | 生态完整、运行时较重 | 前后端语言统一 |
| 典型风险 | Worker/连接数耗尽 | Goroutine 泄漏、无界并发 | 线程池排队、堆和 GC 压力 | CPU 任务阻塞事件循环 |
同一个聚合接口
假设接口需要同时查询用户、订单和推荐:
1 | 接收请求 |
PHP-FPM 可以顺序调用,也可借助异步客户端或任务系统;Go 常用 Goroutine 与 Context;Java 可用线程池、CompletableFuture 或响应式方案;Node.js 常用 Promise.allSettled。无论语言如何,都必须限制并发、设置超时并处理部分失败。
技术选型看什么
- 团队已有能力与维护成本。
- 业务是 CRUD、CPU 计算还是大量长连接。
- 依赖生态、合规和交付周期。
- 可观测性、部署方式与故障恢复能力。
- 数据库和下游服务能承受的并发上限。
PHP 很适合快速交付管理后台和业务系统;Go 适合网络服务、网关和高并发任务;Java 适合复杂领域和成熟企业生态;Node.js 适合 BFF、实时接口和前后端协同。它们都能做大多数 Web 系统,最终差异常来自工程治理,而不是语言排行榜。
共同的容量边界
任何模型都不能绕过这些限制:
- CPU、内存、文件描述符和网络带宽有限。
- 数据库连接数和第三方接口配额有限。
- 无界队列只会把拒绝变成更晚的崩溃。
- 重试必须有次数、退避、抖动和总时限。
- 共享状态需要正确同步或外置存储。