服务调用为什么大多基于 TCP:数据库、RPC、HTTP 与资源复用
一、先说结论
这一篇主要回答三个经常一起出现的工程问题:
- 为什么数据库连接、RPC、HTTP 调用大多基于 TCP,而不是 UDP?
- RPC 为什么有的基于 HTTP,有的基于 TCP?
- 项目里为什么要用连接池、线程池、长连接?
如果先把主线压缩成几句话,可以这样记:
- 数据库、RPC、HTTP 这类调用,更重视数据完整、可靠、有序地到达
- 所以它们更依赖可靠传输能力,而 TCP 是最成熟、最常见的方案
- 基于 HTTP 的 RPC 更重生态兼容性,基于 TCP 的 RPC 更重性能和协议控制力
- 连接池、线程池、长连接本质上都是“昂贵资源不要反复新建”
二、为什么数据库连接、RPC、HTTP 调用大多基于 TCP,而不是 UDP
核心原因是:
这些场景通常都要求应用看到的数据必须完整、正确、有序。
例如:
- 一条 SQL 不能只传一半
- 一次 RPC 调用不能参数丢失、顺序错乱
- 一个 HTTP 响应如果少一段,JSON、HTML、文件内容都可能直接损坏
而 TCP 天然提供:
- 面向连接
- 可靠传输
- 有序交付
- 超时重传
- 流量控制
- 拥塞控制
所以工程上最省事的做法就是:
站在 TCP 这个可靠传输能力之上,再去封装数据库协议、RPC 协议、HTTP 协议。
UDP 就完全不行吗
也不是。
更准确地说:
这些场景不是“非 TCP 不可”,而是“非可靠传输能力不可”。
如果用 UDP,也可以在应用层自己补上:
- 重传
- 去重
- 顺序控制
- 分片重组
- 超时处理
- 流量控制
- 拥塞控制
但复杂度会明显上升,所以大多数业务不会这么做。
为什么游戏、直播、语音更常用 UDP
因为这类场景通常更关心:
- 实时性
- 低延迟
- 少量丢包可接受
例如一帧视频晚 2 秒到,很多时候已经没意义了;这时“补发”反而不如“尽快往前走”。
所以:
- 数据库 / RPC / HTTP 更偏可靠性
- 游戏 / 直播 / 语音更偏实时性
三、RPC 为什么有的基于 HTTP,有的基于 TCP
这个问题本质上是在问:
服务调用更优先考虑生态兼容性,还是更优先考虑性能与控制力?
1. 基于 HTTP 的 RPC
优点主要在于:
- 能直接复用现有 Web 生态
- 更容易通过网关、代理、负载均衡、TLS 等基础设施
- 调试方便,curl / Postman / 浏览器都能直接参与
- 跨语言、跨团队协作成本更低
这类方案更适合:
- 前后端分离
- 对外开放 API
- 云原生 / 网关体系完善的场景
- 强调可观测性和标准化的团队
2. 基于 TCP 的 RPC
优点主要在于:
- 协议可以更轻量
- 二进制格式可完全自定义
- 头部开销更小
- 连接管理、心跳、编解码都能精细控制
- 在纯内网高性能场景下常有更好吞吐和更低延迟
这类方案更适合:
- 纯内网
- 高频调用
- 低延迟要求高
- 有能力维护自定义协议栈的系统
3. gRPC 为什么经常被单独提出来
gRPC 是一个很典型的折中方案:
- 协议上跑在 HTTP/2 之上
- 数据格式常用 Protobuf
- 既有 HTTP 生态支持
- 又有较强性能表现
所以它可以理解成:
在“通用性”和“高性能”之间做折中。
四、项目里为什么要用连接池、线程池、长连接
这三个经常一起问,因为它们背后的工程思想很像:
昂贵资源不要反复创建,应该复用并且可控地使用。
1. 连接池:复用已经建好的连接
无论是数据库连接、HTTP 连接还是 RPC 连接,新建连接通常都不便宜,可能涉及:
- TCP 三次握手
- TLS 握手
- 认证与初始化
- 内核资源分配
所以连接池的价值在于:
- 提前准备一批连接
- 请求来了直接拿现成连接使用
- 用完后放回池中
这样可以降低:
- 建连耗时
- 断连耗时
- 系统抖动
- 下游服务连接压力
2. 线程池:复用工作线程并限制并发度
如果每个请求都新建线程,会带来:
- 线程创建开销
- 内存占用上升
- CPU 上下文切换暴增
- 系统高并发时更容易抖动甚至雪崩
线程池的作用是:
- 提前准备工作线程
- 把任务交给线程池调度
- 通过队列、拒绝策略、最大线程数控制并发
本质上它解决的是:
线程资源太贵,而且不能无限开。
3. 长连接:复用 TCP 生命周期
如果每次请求都:
- 建连接
- 发请求
- 收响应
- 断连接
那么每次都要承担:
- 三次握手
- 四次挥手
- TIME_WAIT
- HTTPS 场景下的 TLS 握手
长连接的价值在于:
一次建连,后续多次请求继续复用。
这样可以减少:
- 握手开销
- 延迟
- TIME_WAIT 数量
- 端口与内核资源压力
4. 三者的共同本质
| 机制 | 解决什么问题 | 核心思想 |
|---|---|---|
| 连接池 | 连接建立/销毁太贵 | 复用连接 |
| 线程池 | 线程建立/销毁太贵 | 复用线程 |
| 长连接 | TCP 频繁握手太贵 | 复用连接生命周期 |
所以它们其实都属于:
池化 + 复用 + 限制资源抖动
五、面试里怎么回答会比较顺
如果面试官把这几题放在一起问,可以这么答:
数据库连接、RPC、HTTP 调用大多基于 TCP,主要是因为这些场景要求请求和响应能够完整、可靠、有序地到达,而 TCP 天然提供确认应答、重传、流量控制和拥塞控制等能力。RPC 之所以有的基于 HTTP、有的基于 TCP,本质上是在通用性和性能之间取舍:基于 HTTP 的 RPC 更方便复用 Web 生态、网关、代理和调试工具,而基于 TCP 的 RPC 往往协议更轻、性能更高、控制力更强。项目里使用连接池、线程池和长连接,则是为了避免昂贵资源被高频重复创建,降低握手、建连、建线程等成本,并让系统在高并发场景下更稳定。
六、一句话总结
可以把这篇文章压缩成一句话:
服务调用链路为什么这样设计,本质上是在“可靠性、性能、生态兼容性和资源成本”之间做工程取舍。
