webman 连不上 mongodb 主因是 php cli 环境未启用 mongodb 扩展,需用 php -m 和 php --ini 确认配置,直连 mongodb\client 并配置连接池与超时,避免使用 jenssegers 封装。

Webman 项目里连不上 MongoDB,90% 不是代码写错了,而是 PHP CLI 环境根本没装 mongodb 扩展,或者扩展加载了但配置错位。
php-cli 是否真正加载了 mongodb 扩展
Webman 的启动、定时任务、命令行导入数据,全部走的是 php-cli,和 Web 请求用的 php-fpm 完全是两套环境。改了 php-fpm 的 php.ini,对 Webman 启动毫无作用。
- 执行
php -m | grep mongodb,无输出 → 扩展未启用 - 执行
php --ini查看Loaded Configuration File路径,打开对应php.ini,确认存在extension=mongodb(不是extension=php_mongo.dll,那是旧版驱动) - Docker 用户必须在
Dockerfile中显式安装扩展:pecl install mongodb+docker-php-ext-enable mongodb;仅composer require jenssegers/mongodb完全没用
别用 jenssegers/mongodb 封装,直连 MongoDB\Client
jenssegers/mongodb 是 Laravel 适配层,Webman 里直接用它容易踩隐性坑:连接复用混乱、超时参数不生效、批量操作被转成低效单条调用。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 连接应使用原生
MongoDB\Client,示例带认证、连接池与超时: $client = new \MongoDB\Client('mongodb://user:pass@127.0.0.1:27017', ['connectTimeoutMS' => 5000, 'socketTimeoutMS' => 30000, 'minPoolSize' => 5, 'maxPoolSize' => 20]);- 不要在每次请求中
new Client,应作为容器服务单例注入,避免反复建连 - 若用副本集,连接字符串必须带
?replicaSet=rs0,否则写入可能静默失败
非结构化数据查询慢?先看 explain("executionStats")
查 100 万条订单按 status 和 created_at 分页很慢?别急着加索引,先看是否命中了索引扫描(IXSCAN),还是在全表扫(COLLSCAN)。
- 在 MongoDB Shell 中执行:
db.orders.find({status:"paid"}).sort({created_at:-1}).limit(20).explain("executionStats") - 重点看:
executionStats.executionStages.stage === "IXSCAN",且nReturned接近totalDocsExamined - 若
nReturned远小于totalDocsExamined,说明索引没覆盖查询字段,要补上投影字段,比如加.project(["id", "amount", "status"]) - 复合索引需匹配查询顺序,例如
{status: 1, created_at: -1}才能支撑find({status:"paid"}).sort({created_at:-1})
海量非结构化文档写入时避免逐条 save()
Webman 接口接收一批日志或事件数据,用 Model::create() 循环(来自 jenssegers/mongodb)本质是 N 次 round-trip,性能断崖式下跌。
- 改用原生
bulkWrite(),一次网络往返完成多条插入/更新 - 注意:
bulkWrite默认有序执行,若允许部分失败可设ordered: false - 每批大小建议控制在 1000 条以内,过大易触发
maxMessageSizeBytes限制(默认 48MB) - 写入前确保目标字段类型一致,避免因 BSON 类型混杂导致
bulkWrite中断
最常被忽略的一点:非结构化数据往往字段动态、嵌套深,但 explain 只告诉你“有没有走索引”,不告诉你“投影字段是否被索引覆盖”——哪怕用了 .project(),如果索引没包含这些字段,WiredTiger 仍要回表读取完整文档。










