codeigniter 不支持原生数据库连接池,pconnect 仅复用单进程连接,无法限流、探活或故障转移;可行方案是多连接组轮询或 redis 缓存降载。

CodeIgniter 本身不提供原生数据库连接池机制,pconnect(持久连接)不是连接池,它只是复用 PHP-FPM 进程内的 MySQL 连接,无法控制数量、超时、健康检查或负载分发 —— 真正的连接池必须由外部组件(如 ProxySQL、MySQL Router)或应用层模拟实现。
为什么不能直接用 pconnect 当连接池
pconnect 在 CodeIgniter 中设为 TRUE 后,每个 PHP 进程只会建立一次连接并复用,但存在几个硬伤:
- 无法限制最大连接数,高并发下容易打满 MySQL 的
max_connections - 连接空闲超时由 MySQL 的
wait_timeout控制,PHP 层无法主动回收或探测失效连接 - 没有故障转移能力:某个连接断开后,后续请求仍可能尝试使用它,导致
MySQL server has gone away - 不同连接组(如
pool_1、pool_2)之间不共享状态,无法实现真正的“池化调度”
用多个预定义连接组 + 手动轮询模拟连接池
如果你无法部署 ProxySQL 或 Redis 代理,最接近“连接池效果”的做法是:在 application/config/database.php 中定义多个独立连接组,并在运行时按需选择一个可用连接。这不是标准连接池,但能缓解单点压力。
示例配置片段:
$db['pool_0'] = [
'hostname' => '192.168.1.10',
'username' => 'app_user',
'password' => 'xxx',
'database' => 'mydb',
'dbdriver' => 'mysqli',
'pconnect' => FALSE, // 关键:禁用持久连接,避免僵尸连接堆积
'db_debug' => FALSE,
'failover' => [],
];
$db['pool_1'] = [
'hostname' => '192.168.1.11',
'username' => 'app_user',
'password' => 'xxx',
'database' => 'mydb',
'dbdriver' => 'mysqli',
'pconnect' => FALSE,
'db_debug' => FALSE,
'failover' => [],
];
使用时手动轮询(比如用取模或随机):
- 维护一个轻量级计数器或用
microtime(true)做简单哈希 - 每次调用
$this->load->database('pool_'.$index, TRUE)获取独立 DB 实例 - 注意:每个
TRUE返回的实例都占用独立连接,务必在用完后显式关闭($db->close()),否则连接泄漏
真正可行的高并发方案:用 Redis 缓存 + 查询结果复用
与其花精力模拟连接池,不如把数据库连接数压到最低 —— 大部分读请求根本不需要实时连库。CodeIgniter 4 的缓存系统配合 Redis 是更实际的选择:
- 在
.env中启用:CACHE_HANDLER=redis,并配置REDIS_HOST、REDIS_PORT - 对非敏感、变化频率低的数据(如配置表、分类列表、用户权限树),统一走
cache('key')读取 - 写操作后主动清除相关缓存:
cache()->delete('user_profile_'.$uid) - 避免在循环中反复调用
cache()->save(),合并批量写入
这样即使数据库只有 20 个连接,也能支撑数千 QPS 的读请求 —— 这才是 CodeIgniter 场景下更可控、更易监控的“高并发路径”。
复杂点在于:连接池的“健康探活”和“自动扩容”逻辑必须自己补全,而 CodeIgniter 没有钩子让你拦截所有 query() 调用做连接重试。别试图在框架里造轮子,优先用好它的缓存抽象和外部中间件。











