用 microtime(true) 在关键环节(如数据库、外部 api 调用前后)打点并 error_log 记录,结合上下文标识精准定位真实瓶颈,避免误判 php 执行慢。

怎么用 microtime(true) 定位真实瓶颈
接口慢,不等于 PHP 执行慢——可能是数据库、外部 API 或网络 IO 拖累。光看整体响应时间没用,得把耗时拆到每个环节。
在关键位置插 microtime(true) 是最轻量、最准的手段。别只在入口和出口打点,要在 callExternalApi() 前后、getDataFromDatabase() 前后都加,否则你会误判“PHP 太慢”,其实只是微信登录接口卡了 3 秒。
- 每次打点后立刻写入
error_log(),别攒着 echo 或返回 JSON,避免缓冲干扰时间精度 - 注意
microtime(true)返回的是浮点秒,不是毫秒,别直接跟前端监控的 ms 单位对齐而手动 ×1000——容易算错 - 日志要带上下文标识,比如
"[order_create] db_query: 0.42s",否则多接口混在一起根本分不清谁是谁
为什么 cURL 调第三方接口总超时?
不是对方服务器慢,大概率是你没设对超时参数。默认 curl_exec() 会无限等下去,一个挂掉的短信网关就能拖垮整个订单流程。
CURLOPT_TIMEOUT 和 CURLOPT_CONNECTTIMEOUT 必须显式设置,且要区分:前者是整次请求最大耗时(含 DNS、握手、传输),后者仅控制建连阶段。生产环境建议设为 3 和 1,而不是笼统地全设成 5。
立即学习“PHP免费学习笔记(深入)”;
- 别用
set_time_limit(0)来“解决”超时——它掩盖问题,还可能让 PHP-FPM 进程卡死不释放 - 如果多个外部调用串行执行,总耗时就是累加的;改用
curl_multi_init()并行发,但要注意对方是否限流,盲目并发可能被封 IP - 记录
curl_getinfo($ch, CURLINFO_HTTP_CODE)和CURLINFO_RESPONSE_CODE,HTTP 状态码异常(如 502/504)比耗时更早暴露网关或 Nginx 层问题
缓存不是加个 Redis::set() 就完事
加缓存本意是降延迟,但用错方式反而引入新延迟:比如缓存穿透导致大量空查询打到 DB,或者缓存雪崩让瞬间流量压垮从库。
高频读接口必须配二级防护:Redis 存结果 + 本地内存缓存(apcu) 挡穿透。查缓存先走 APCu,命中直接返回;未命中再查 Redis;Redis 也没才查 DB,并把结果同时写回两级缓存。
- 缓存 key 要包含业务维度,比如用户 ID 或地区,别用固定字符串,否则 AB 测试或灰度发布时数据互相污染
-
Redis::set($key, $data, ['ex' => 60])这种写法没问题,但过期时间不能拍脑袋定——库存类数据缓存 5 分钟可能超卖,配置类数据缓存 24 小时又太长 - 别在事务里写缓存,尤其是涉及
INCRBY的扣减逻辑,缓存和 DB 不一致会直接引发资损
高并发下 PHP-FPM 进程池配置为什么比代码还重要
再快的 PHP 代码,卡在 FPM 进程排队里也白搭。看到大量请求 504 Gateway Timeout 或 Nginx 日志里出现 upstream timed out,基本就是 FPM 吃紧了。
重点调三个参数:pm.max_children 决定最多能起多少 worker;pm.start_servers 控制启动时预热数量;pm.max_requests 防止内存泄漏积累——设太小会频繁重启进程,设太大又可能累积泄露。
- 别照搬网上“CPU 核数 × 4”这种公式,实际要看平均请求内存占用。用
ps aux --sort=-%mem | grep php-fpm看单个进程 RSS,再按服务器总内存反推max_children -
pm = dynamic比static更稳妥,但pm.min_spare_servers和pm.max_spare_servers差值别超过 10,否则低峰期空转太多进程,高峰期又扩不过来 - 检查
slowlog文件,里面记录的是真正卡住的 PHP 脚本路径和堆栈,比所有性能分析工具都直接
延迟优化不是堆技术,而是层层剥洋葱:先看清哪一层在拖后腿,再动对应那层的开关。很多人一上来就换 Swoole,结果发现慢的是 MySQL 没索引,白忙活。











