mongodb性能瓶颈源于驱动层、索引缺失、wiredtiger缓存配置与负载不匹配;需确认cli环境mongodb扩展已启用,建立覆盖索引如{status:1,created_at:-1},合理设置cachesizegb为物理内存55%~60%,批量写入改用bulkwrite。

Webman 项目里用 MongoDB 存百万级文档时,慢不是因为 Webman,而是 mongodb 驱动层、索引设计、WiredTiger 缓存配置没对齐真实负载。直接调高 cacheSizeGB 或加个索引不解决问题,得看请求模式和内存水位。
确认 PHP CLI 环境已装 mongodb 扩展
Webman 启动和命令行任务(如数据导入、定时清理)都走 php-cli,它和 php-fpm 是两个进程,配置互不影响。很多人改了 php-fpm 的 php.ini,却忘了 php-cli。
- 运行
php -m | grep mongodb,无输出说明扩展未加载 - 执行
php --ini查看Loaded Configuration File路径,确认该php.ini里有extension=mongodb - 若用 Docker,需在
Dockerfile中显式安装扩展,不能只靠composer require jenssegers/mongodb
laravel-mongodb 查询慢,先查是否命中覆盖索引
jenssegers/mongodb 的 where()、orderBy() 最终转成原生 find() 或 aggregate(),但框架不自动建索引。100 万条 orders 表按 status 和 created_at 分页查,没索引就会 COLLSCAN。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 在 MongoDB Shell 中运行
db.orders.getIndexes(),确认复合索引存在:{ status: 1, created_at: -1 } - 用
explain("executionStats")验证查询是否IXSCAN:db.orders.find({status:"paid"}).sort({created_at:-1}).limit(20).explain("executionStats") - 如果
executionStats.nReturned远小于executionStats.totalDocsExamined,说明索引没覆盖查询字段,要补上投影字段,比如.project(["id", "amount", "status"])
Webman 多进程下 WiredTiger cacheSizeGB 设置不当导致内存抖动
Webman 默认开多个 worker 进程,每个都连同一个 MongoDB 实例,但 cacheSizeGB 是整个 mongod 进程的全局缓存上限。设太高,OS 内存压力大;设太低,频繁 page eviction,查询毛刺明显。
- 查当前缓存使用率:
db.serverStatus().wiredTiger.cache["bytes currently in the cache"] / db.serverStatus().wiredTiger.cache["maximum bytes configured"] - 生产环境建议设为物理内存的 55%~60%,例如 32GB 机器配
cacheSizeGB: 18(别写成20) - 若发现
tracked dirty bytes in the cache占比持续 >20%,需调大eviction=(threads_max=8),但仅限副本集 4.0+ 版本
批量写入时避免逐条 save() 触发 N 次 round-trip
Webman 接口接收一批日志或事件数据,用 Model::create() 循环插入,实际是 N 次 insertOne,网络和锁开销爆炸。尤其当单次请求带 500 条记录时,耗时从 200ms 拉到 3s+。
- 改用原生
bulkWrite:db.logs.bulkWrite([ { insertOne: { document: { ... } } }, ... ]) - 在
jenssegers/mongodb中对应Model::upsertMany()或直接调Model::getCollection()->bulkWrite() - 每批控制在 100~500 条之间,太大易 OOM,太小起不到合并效果
真正卡住的往往不是语法或框架用法,而是 cacheSizeGB 和 worker 数量之间的隐含冲突——Webman 开 8 个 worker,mongod 却只分了 8GB 缓存,那每个 worker 平均只能摊到 1GB 工作集,而实际热点数据可能就 5GB。这时候加索引、换查询写法,收益远不如调缓存配比来得直接。










