swoole面试考察重在真实问题排查而非背题:启动失败主因是端口占用或权限不足(如非root绑80端口),协程中file_get_contents仍阻塞因未协程化,onworkerstart里new pdo会导致连接数超限,定时器需放onworkerstart中重建。

没有“100道核心面试题”这种标准清单——Swoole 的实际考察从来不是靠背题,而是看你能不能在 swoole_http_server 启不起来、onReceive 收不到数据、协程里 curl_exec 阻塞主线程这些真实场景里快速定位问题。
为什么 swoole_http_server 启动后访问 502 或直接拒绝连接
最常见原因是端口被占用或用户权限不足。Swoole 默认以当前用户身份运行,若监听 80 端口但非 root 用户,会静默失败(日志里可能只写 bind() failed);另一类是 systemd 或 supervisor 启动时没加载环境变量,导致找不到 extension=swoole.so。
- 先用
netstat -tuln | grep :80确认端口空闲 - 开发阶段统一改用大于 1024 的端口,比如
9501 - 检查
php --ri swoole输出是否含enabled和version,避免扩展未真正加载 - 如果用 Docker,确认
EXPOSE和宿主机-p映射一致,且容器内没启用 SELinux 或防火墙拦截
go() 启动的协程里调用 file_get_contents() 为什么还是阻塞
因为 file_get_contents() 是同步 I/O,即使在协程里也会让当前协程挂起,但不会释放 CPU 给其他协程——它底层没走 Swoole 的协程 Hook。真正协程友好的方式是用 Swoole\Coroutine\Http\Client 或 co::readFile()。
-
file_get_contents("http://...")→ 必须换成(new Swoole\Coroutine\Http\Client(...))->get() -
file_get_contents("/path/to/file")→ 改用Swoole\Coroutine::readFile(),注意路径必须是绝对路径 - 第三方 SDK(如 Redis 客户端)必须确认是否支持协程模式,
phpredis不行,ext-redis+Swoole\Coroutine\Redis才行
onWorkerStart 里 new PDO 为什么报 Too many connections
每个 worker 进程都会执行一次 onWorkerStart,如果这里直接 new PDO,等于每个进程都建独立连接,16 个 worker 就占满 MySQL 默认 151 连接上限。这不是连接池没配好,是根本没理解进程模型。
- PDO 实例应延迟创建:在
onReceive或具体请求处理时按需 new,并在处理完后$pdo = null触发析构(但更推荐用连接池) - 生产环境务必用
Swoole\Coroutine\MySQL或Swoole\Runtime::enableCoroutine()+ 第三方协程 MySQL 客户端 - 如果坚持用 PDO,请确保
PDO::ATTR_PERSISTENT => true,但要注意持久连接在 reload 时不会自动清理,可能引发状态残留
swoole_timer_tick() 定时器在 reload 后失效
定时器是绑定到当前 worker 进程的,reload 时旧进程退出,新进程不会自动重建定时器。你以为加了就一直跑,其实只活到下次 reload。
- 把定时器创建逻辑放到
onWorkerStart里,每次新 worker 启动都重新注册 - 避免在
onReceive中重复创建同一定时器(会导致泄漏),可用isset($server->tick_id)做幂等判断 - 长周期任务(如每小时统计)别依赖 tick,改用外部调度(crontab + HTTP 触发)更可靠
真正卡住人的从来不是“会不会写 go()”,而是看到 coroutine id is 0 还以为在协程里,或者把 static $cache = [] 当全局缓存用,结果发现每个 worker 的副本完全不共享——这些细节比题目数量重要得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











