workerman协程数据库超时本质是同步阻塞操作卡死调度,须禁用onworkerstart中new pdo等同步连接,改用swoole协程mysql连接池并合理配置maxactive、idletimeout等参数。

Workerman协程中数据库查询频繁超时,本质是同步阻塞操作混入协程环境导致调度卡死,不是网络延迟或SQL慢——同一Worker内其他请求会集体挂起,top显示CPU低但响应停滞。
确认是否误用同步PDO/MySQLi
检查所有数据库初始化代码,【绝对禁止在onWorkerStart中new PDO()或mysqli_connect()】。这类同步连接一旦创建就长期空闲占用,不归还、不复用,高并发时直接触发MySQL连接数上限,后续请求全部卡在connect timeout。
打开你的Worker启动文件,搜索PDO::、new mysqli、mysql_connect等关键词。只要出现在onWorkerStart回调里,立刻删除或注释掉。
验证方式:临时把所有DB查询替换成go(function () { usleep(100000); });,如果超时现象消失,说明原问题就是同步阻塞压垮了协程调度链。
改用Swoole协程MySQL客户端
第一步:安装Swoole扩展(PHP 8.0+,启用--enable-coroutine编译选项)。
第二步:在onWorkerStart中初始化协程MySQL连接池,而非单连接:
$pool = new \Swoole\Coroutine\MySQL\Pool([<br> 'host' => '127.0.0.1',<br> 'port' => 3306,<br> 'user' => 'root',<br> 'password' => '123456',<br> 'database' => 'test',<br> 'charset' => 'utf8mb4',<br> 'maxIdleTime' => 60,<br> 'maxActive' => 20<br>]);
第三步:在onMessage或控制器中,用$pool->get()获取连接,查询完调用$conn->close()归还,不要手动unset或NULL赋值——池子内部自动回收。
调整连接池关键参数
方法一:控制总连接数不超MySQL上限
查MySQL当前限制:SHOW VARIABLES LIKE 'max_connections';,假设返回200,则Workerman所有Worker进程的连接池maxActive之和不能超过140(200 × 70%)。若你设$worker->count = 8,每个池子maxActive最多配17(向下取整)。
方法二:强制连接生命周期管理
在池配置中加入'maxLifetime' => 1800000(30分钟),避免长连接因MySQLwait_timeout被服务端主动断开;加'idleTimeout' => 600000(10分钟),让空闲连接及时释放,防止池子淤积失效连接。
注意:【maxActive配太大且没设idleTimeout,会导致大量僵尸连接堆积,查询时随机分配到已断开的连接,直接触发超时】。
规避协程上下文中的同步调用
第一步:全局搜索项目中所有$pdo->query(、$mysqli->query(、db_query(等调用点。
第二步:凡是在onMessage、定时器回调、协程函数内部出现的,全部替换为Swoole协程MySQL对象的query()方法。
第三步:Eloquent用户需切换驱动——禁用PDO::ATTR_PERSISTENT => true,Capsule初始化时传入['driver' => 'mysql', 'host' => ...],底层必须走Swoole\Coroutine\MySQL,不能包装PDO。











