首页 / 知识库 / python服务端进阶 / 服务端高并发优化

05 - 池化技术

这一章讲一个朴素但极其有效的思想:复用。频繁地「创建 → 用一次 → 销毁」是巨大的浪费,池化就是「造好一批放着,反复借用」。

一句话先记住:池化就是「预先造好一批昂贵的资源,用完还回来、下次接着用」,省掉反复创建销毁的开销。


5.1 为什么要池化:创建资源很贵

以数据库连接为例,建立一个连接要经历:

建立一个 PostgreSQL 连接的成本:
  1. TCP 三次握手           (网络往返)
  2. TLS 握手(如果加密)     (更多往返)
  3. 数据库身份认证          (用户名密码校验)
  4. 分配会话内存、初始化       
  ────────────────────────
  可能要几毫秒到几十毫秒

如果每个请求都「建连接 → 查一次 → 关连接」,在高并发下光是建连接就把时间和资源耗光了。

不用连接池(每次现建):
  请求1: [建连接 20ms][查询 2ms][关连接]
  请求2: [建连接 20ms][查询 2ms][关连接]
  ...   90% 的时间浪费在建连接上!

用连接池(复用):
  请求1: [借连接 0.01ms][查询 2ms][还连接]
  请求2: [借连接 0.01ms][查询 2ms][还连接]
  ...   几乎所有时间都花在真正干活上

5.2 池化的通用模型

所有「池」都是同一套思路:

        ┌─────────────────────────┐
        │         资源池             │
        │  [空闲][空闲][占用][占用]   │
        └───────────┬─────────────┘

   借 (acquire) ────┤──── 还 (release)

              ┌─────┴─────┐
              │  请求们排队  │  ← 池空了就等,或拒绝
              └───────────┘

关键参数:
· 最小连接数:预热时先建这么多
· 最大连接数:最多建到这么多(超过就排队/拒绝)
· 空闲超时:太久没用的连接回收掉
· 获取超时:借不到连接等多久就报错

5.3 后端里常见的三种池

1. 数据库连接池(最重要)

FastAPI + PostgreSQL 场景下,用 SQLAlchemy / asyncpg 都自带连接池。关键是把参数配对:

连接池大小怎么定?(经验起点)
  连接数 ≈ 数据库 CPU 核数 × 2  (再根据压测微调)

⚠️ 常见误区:连接数不是越大越好!
   PostgreSQL 每个连接都占内存、占进程资源。
   连接开太多,数据库自己先被压垮。

如果应用有很多实例(水平扩展后),每个实例都开一个池,总连接数可能爆掉数据库上限。这时要用 PgBouncer 这类「连接池中间件」在数据库前面统一管理。

2. 线程池

CPU 密集或阻塞型任务,用固定数量的线程处理,避免「无限开线程」把系统拖垮。

3. 协程池 / 并发限制

异步框架里虽然协程很轻,但也不能无限开。常用信号量(Semaphore) 限制同时进行的并发数,避免瞬间打爆下游。

用信号量限制同时最多 100 个并发请求下游:
  第 101 个请求 → 排队等前面的完成
  → 保护下游服务不被打垮

5.4 池化的核心权衡

池子开多大,是个平衡:

池子太小:              池子太大:
· 请求排队等连接         · 占用大量资源(内存、连接)
· 高峰期借不到 → 超时     · 下游(数据库)被过多连接压垮
· 吞吐上不去             · 反而更慢

        ↓ 正确做法 ↓
   压测找到「刚好够用」的大小

重要认知:连接池大小是要压测调出来的,不是拍脑袋定的。太小吞吐不够,太大反而拖垮下游。


本章小结

你要记住要点
池化本质预先造好昂贵资源,反复借用,省掉创建销毁开销
通用模型借(acquire)→ 用 → 还(release),有最大/最小/超时参数
三种池数据库连接池(最关键)、线程池、协程/并发限制
连接数误区不是越大越好,太大会压垮数据库
核心权衡池子大小靠压测调出「刚好够用」

下一章预告:单机榨干了还不够,就该「加机器」了——负载均衡怎么分流,读写分离怎么减轻数据库压力。


上一章 ← 04 - 异步化与削峰 | 下一章 → 06 - 读写分离与负载均衡