codeigniter并发能力取决于php-fpm配置、数据库连接策略、缓存设计等;需合理设置pm.max_children、禁用pconnect、用redis替代mysql计数、会话与缓存必须使用redis。

CodeIgniter 本身不处理大规模并发,它只是被动响应请求;真正的并发能力取决于 PHP 运行模式、Web 服务器配置、数据库连接策略和缓存设计 —— 框架层能做的,是避免成为瓶颈。
PHP-FPM 进程模型决定并发上限
CodeIgniter 运行在 PHP-FPM 上时,pm.max_children 直接卡死并发请求数。比如设为 50,哪怕 Nginx 能扛 1000 QPS,第 51 个请求就得排队等空闲 worker。
- 不要盲目调高
pm.max_children:内存会线性上涨,每个 worker 常驻 20–40MB,100 个就是 2–4GB - 优先调优
pm.start_servers和pm.min_spare_servers,让空闲 worker 数量贴合日常流量波峰 - 启用
pm.status_path(如/fpm-status),用curl http://localhost/fpm-status?full实时看 busy/idle workers 分布 - 注意
request_terminate_timeout:长耗时脚本(如导出)卡住 worker,会导致后续请求全部堆积
数据库连接不能靠 pconnect 抗并发
pconnect 在 CodeIgniter 中设为 TRUE 后,只是复用单个 PHP-FPM worker 内的连接,不是连接池 —— 它既不限流,也不探活,更不支持故障转移。
- 高并发下
wait_timeout(MySQL 默认 8 小时)远大于 PHP 请求生命周期,连接常处于“假死”状态,下次复用直接报MySQL server has gone away - 真正有效的做法是:禁用
pconnect(设为FALSE),改用多个预定义连接组 + 轮询选择,例如$this->load->database('pool_'.($i % 3), TRUE) - 每次用完必须显式调用
$db->close(),否则连接不会释放回系统,max_connections很快打满 - 更推荐方案:把读请求压到 Redis 缓存,连库操作降到最低 —— 大部分列表页、详情页的“数据”根本不需要实时查库
计数类写操作必须绕过 MySQL 行锁
像文章阅读量、商品销量这类高频递增场景,直接用 $db->query("UPDATE posts SET views = views + 1 WHERE id = ?") 会引发严重行锁竞争,QPS 上百就明显延迟。
-
cache()->increment()不可靠:文件驱动不支持原子操作;Redis 驱动虽调INCR,但默认不设 TTL,key 永久存在导致内存泄漏 - 正确做法是直连 Redis,用 Lua 脚本封装原子逻辑:
INCRBY+ 首次写入才EXPIRE,确保 key 自动过期不堆积 - 同步回 MySQL 必须异步:按天分片 key(如
post:123:views:20260512),凌晨定时任务批量聚合后用INSERT ... ON DUPLICATE KEY UPDATE落库 - 前端要过滤非真实用户:检查
$_SERVER['HTTP_USER_AGENT']是否含爬虫标识,再结合 Session/cookie 做 24 小时去重,避免刷量干扰
会话和缓存必须脱离文件存储
默认的 file 会话和 file 缓存在多机器负载均衡下完全失效,且高并发时磁盘 I/O 成为瓶颈。
- 会话必须切到 Redis 或数据库:在
app/Config/Session.php中设$handler = 'redis',并配好$savePath(如tcp://127.0.0.1:6379?database=1) - 缓存驱动必须禁用
file:env文件里明确写cache.handler = redis,别依赖框架默认值 - Redis 连接失败时,
cache()默认静默降级为 dummy 驱动,业务无感知但缓存全失效 —— 要加日志监控cache()->getInfo()的返回值是否包含connected => true - 不要在控制器里反复调
cache('key'):先$cache = cache(),再复用对象,减少服务定位开销
高并发不是堆配置能解决的,关键是识别哪些操作真需要实时、哪些可以妥协为最终一致 —— 比如阅读量允许 5 分钟延迟,那就不该让每次请求都碰一次 Redis;而用户登录态必须强一致,那就得用带健康检查的 Redis Sentinel 集群,而不是单点。











