3. 性能问题定位与优化思路
回答框架图:PHP 性能分析四步法
面试官常问“服务器负载高怎么办”或“接口慢如何排查”。掌握下面这张回答路径图,可以快速组织语言,展示系统性能力。
问答卡片 1
面试问题:线上 PHP-FPM 进程数飙高,CPU 使用率 90%,你从哪里开始排查?
面试官考察点:性能排查流程、工具链(top/strace/慢日志)、问题优先级判断。
- 现象确认:确认 CPU 高、进程数异常。
- 资源层面:检查 MySQL 慢查询、Redis 是否阻塞、磁盘 I/O。
- 代码层面:开启 slow log,定位耗时函数;使用 Xdebug 或 Blackfire 分析。
- 解决验证:加缓存 / 优化算法 / 提升连接池配置,压测对比。
简短示例回答:先看 top 确认 CPU 消耗在 PHP-FPM 进程;然后用 strace -p 看系统调用是否卡在等待锁;同时查看 slow log 找出最耗时的请求。发现是某个秒杀接口每次查全表,加了 Redis 缓存并限流后 CPU 降到 30%。
可能追问:“如果 slow log 没有输出,怎么进一步定位?”(答案:启用 opcache 的 profiler、xhprof 采样)。
问答卡片 2
面试问题:如何优化一个查询耗时 5 秒的接口?
面试官考察点:数据库索引、SQL 调优、分页与缓存策略。
- 抓慢 SQL:在数据库开启 slow query log 或使用 ORM 的日志。
- 分析执行计划:看 type / rows / Extra 是否全表扫描、文件排序。
- 索引优化:增加复合索引覆盖查询字段;避免索引失效(如函数处理字段)。
- 应用层缓存:考虑 Redis 缓存热点数据,必要时用 Elasticsearch 替代组合查询。
简短示例回答:先找到慢查询是 SELECT * FROM order WHERE status=0 ORDER BY create_time DESC LIMIT 100000,20;执行计划显示 filesort,利用覆盖索引 status + create_time + id 消除排序,并用 WHERE id > 上一页最大id 优化深度分页,接口耗时降至 50ms。
可能追问:“如果索引已经用到极致还是慢,下一步怎么做?”(答案:垂直分表、引入该数据的缓存、改为异步处理)。
问答卡片 3
面试问题:PHP 中的 opcache 如何影响性能?怎样合理配置?
面试官考察点:opcache 原理、常见配置项、缓存失效场景。
- 原理:opcache 将 PHP 脚本编译后的 opcode 共享在内存中,减少重复编译。
- 关键配置:memory_consumption(建议 128M~256M);max_accelerated_files(建议 2000~10000)。
- 验证:通过 opcache_get_status() 查看 hits/misses;用 opcache_reset() 手动清理。
- 避坑:代码文件修改后 opcache 过期延迟,开发环境建议关掉或设 validate_timestamps=1。
简短示例回答:opcache 默认 memory_consumption=64M 可能不够大流量项目,我调到 256M 并设置 max_accelerated_files=10000。部署时通过 Webhook 调用 opcache_reset() 避免旧代码生效;线上缓存命中率从 80% 提升到 99%,QPS 提高 40%。
可能追问:“部署自动化脚本中如何处理 opcache 预热?”(答案:在 deploy 后执行一遍 curl 请求所有业务核心路由,或使用 opcache_compile_file 提前编译)。
知识结构表格:性能优化工具速查
| 场景 | 工具/命令 | 核心关注点 |
|---|---|---|
| CPU 高 | top, strace, xhprof | 确认是用户态还是内核态;函数调用频次 |
| 内存泄露 | pmap, memprof, valgrind | 内存持续增长不释放;循环引用未解除 |
| 慢 SQL | EXPLAIN, slow query log, pt-query-digest | 扫描行数、索引使用情况、排序方式 |
| I/O 等待 | iostat, iotop, vmstat | 磁盘读写延迟、队列长度 |
| 外部服务 | curl -w, tcpdump, ngx_http_upstream_check_module | 连接超时、请求耗时分布 |