刚写后端的人常被这几个词绕住:接口文档写「支持高并发」,面试问「并发和并行的区别」,上线又被要求「高可用、可分布式部署」。这篇不堆定义,先把三个层次的问题分开,再给一份自查清单和排查顺序,让你遇到具体需求时能判断该动哪一层、什么情况下这些说法其实不适用。
刚写后端的人常被这几个词绕住:接口文档写着「支持高并发」,面试官问「并发和并行的区别」,上线又被要求「高可用、可分布式部署」。这些词被混着用,导致很多人一遇到性能问题就想着加线程、拆服务,方向从一开始就错了。
这篇不堆定义,先把三层问题分开:代码层的任务调度、系统层的请求规模、部署层的冗余能力。分清楚之后再给一份自查清单和排查顺序,让你遇到具体需求时能判断该动哪一层,以及什么情况下这些说法其实不适用。
先把三层问题分开:语言层的并发、系统层的并发量、部署层的高可用
- 并发
- 多个任务在时间上交替推进,单核也能做到,重点是调度而不是同时进行
- 并行
- 多个任务在同一时刻真正一起执行,依赖多核或多机资源,是物理事实
- 高并发
- 同一时间涌入的请求规模很大,描述的是系统承受的压力,不是代码写法
- 高可用
- 部分组件出故障时服务仍能继续提供,靠冗余和切换实现,与流量大小无关
- 分布式
- 把系统拆到多台机器上协作,是解决规模和可用性的手段之一,本身不是目标
- 并发是任务调度的概念,并行是执行资源的物理事实,两者在单核、多核、异步 IO 下会有不同组合;写了异步代码不代表就有并行
- 高并发描述的是同时涌入的请求规模,落在系统层;单机开很多线程不等于扛得住并发,线程多了反而可能把内存和上下文切换拖垮
- 高可用讲的是出故障时还能不能提供服务,属于部署与冗余层面,和并发、并行可以彼此独立存在:低流量系统同样需要高可用
- 分布式是手段不是目的,它引入的一致性、网络分区、链路追踪代价很实在,很多小团队根本用不上,硬上只会先被运维复杂度拖垮
自查清单:你这套系统到底卡在哪一层
判断放在哪一层,别靠感觉,靠几个可观察的信号。先量单请求延迟基线,再统计单位时间的请求量,最后看故障发生的形态,三条线分开看,基本就能定位到层次。
| 现象 | 更可能卡在哪层 | 先看的动作 |
|---|---|---|
| 单个接口调用本身就慢 | 语言层与下游依赖 | 拆解请求内部耗时,找出慢在哪一段 |
| 平时正常,量一上来就超时 | 系统层容量与排队 | 看是否限流排队、共享资源是否打满 |
| 周期性整体不可用 | 部署层可用性 | 查健康检查、切换演练、单点依赖 |
| 跨机器数据对不上 | 分布式一致性 | 先确认是否真的需要拆到多机 |
- 先在 接口测速(/tools/speed-test) 量一遍单请求延迟基线,判断慢是单次耗时问题还是排队问题,两者解法完全不同
- 看错误码分布:超时、限流、连接被拒往往指向并发与容量,而周期性整体不可用更可能是可用性问题
- 数一数共享资源:数据库连接池、锁、外部接口配额,绝大多数所谓高并发故障,实际是共享资源被打满
- 确认团队规模与运维能力:三五人小团队上分布式部署,往往先被运维复杂度拖垮,而不是被流量拖垮
排查顺序:从下往上,别一上来就改架构
- 第一步:看单请求耗时把一次请求内部各段耗时打点出来,确认慢在自身逻辑还是下游依赖;慢请求堆着不放手,线程再多也是白搭。
- 第二步:看限流与排队检查入口有没有限流、有没有排队策略;缺少排队时并发一冲上来就是雪崩,这时候扩容只是把雪崩往后推。
- 第三步:看降级路径确认非核心依赖能不能降级、降级后功能是否还能用;有降级能顶住的前提下,再谈扩容才有意义。
- 第四步:才考虑拆分与分布式只有单机容量、可用性冗余都到瓶颈时才值得付出这份复杂度;拆之前先想清楚跨节点一致性和链路追踪怎么收。
放在 Java 语境里看:多线程只是其中一块
Java 里谈并发,容易一上来就想到线程池、锁、异步编排。这些解决的是任务怎么并发跑,属于语言与框架层,不等于系统能扛多大流量。真正决定吞吐的,常常是连接池大小、超时设置、是否阻塞等待这些更朴素的东西。
| 层面 | 典型手段 | 它不负责的事 |
|---|---|---|
| 语言与框架层 | 线程池、锁、异步编排 | 不决定系统整体容量上限 |
| 连接与资源层 | 连接池、超时、队列长度 | 不解决下游本身的能力瓶颈 |
| 部署与冗余层 | 多实例、健康检查、切换 | 不优化单次请求的响应速度 |
- 线程池、锁、异步编排解决的是任务怎么并发跑,上线前要压测确认瓶颈是在线程、连接池还是下游接口
- 连接池大小、超时设置、是否阻塞等待,往往比多开线程更能决定实际吞吐,调参前先量基线
- 涉及外部 API 或中转站调用时,并发上限以服务端实际返回的限流为准,具体数字到 中转站目录(/sites) 与对应说明页核对
- 把「我用了多线程」当成并发问题已解决,是很常见的误判,压测结果才算数
三个常见误区与对应做法
- 把并发数当成用户数:并发是同一时刻在处理的任务量,用户总量大但请求稀疏时压力并不高,先分清再定容量目标
- 把高可用当成加机器:没有健康检查、没有故障切换演练,机器再多也可能一起倒,冗余要配可验证的切换动作
- 把分布式当成性能优化:单体先压测到瓶颈再拆,拆完要准备好处理跨节点一致性与链路追踪,否则问题只会从一台机器扩散到一群机器
先分清楚是任务调度问题、容量问题还是冗余问题,再决定动代码、动参数还是动架构。下一步想验证自己这套调用到底卡在哪一层,可以先用测速工具量一遍单请求延迟基线,再去中转站目录核对各家的限流与可用性说明,用真实数字代替感觉。→
常见问题
并发和并行到底怎么区分?
并发是多个任务在时间上交替推进,强调调度与切换;并行是多个任务真的在同一时刻由不同执行单元跑,强调物理资源。单核也能写出并发代码,但单核不会有真正的并行。判断时先问「同一瞬间有没有两个任务在算」,答案是有才是并行。
高并发和高可用是一回事吗?
不是。高并发说的是同时来很多请求,考验容量与排队能力;高可用说的是出故障时还能不能用,考验冗余与切换能力。一个系统可能并发能力很强但一挂就全挂,也可能流量很小但做了多活。两者要分开评估,扩容解决前者,冗余和演练解决后者。
小团队一定要上分布式吗?
不一定。分布式主要解决单机容量上限和可用性冗余,代价是一致性、调试和运维复杂度上升。如果业务量还没到单机瓶颈,先把超时、限流、降级、监控做好,收益通常更大。等到单机压测确实顶不住、或者业务要求故障不中断时,再考虑拆。