hyperf 默认不支持 mongodb,需通过 hyperf/mongodb 扩展接入,依赖官方 mongodb/mongodb 包及 php mongodb 扩展(非已废弃的 mongo),安装时须确保 php 8.1+ 对应 mongodb 扩展 ≥1.15.0,并在 swoole 5.x 下禁用 swoole_hook_curl;连接池按数据库名隔离,多集群需配置多个独立 pool;海量写入推荐直连 collection 并控制 batchsize;所有操作必须在协程内执行,禁止在 defer/onfinish 等非协程上下文中调用。

Hyperf 默认不支持 MongoDB,必须通过 hyperf/mongodb 扩展接入,且不能直接复用 Laravel 的 MongoDB\Driver\Manager 或原生 PHP 驱动连接逻辑。
安装 hyperf/mongodb 并确认 Swoole 兼容性
这个扩展底层依赖 mongodb PHP 扩展(即官方的 mongodb/mongodb 包),不是 mongo(已废弃)。若你执行 pecl install mongodb 失败,大概率是 PHP 版本或 Swoole 环境不匹配:
- PHP 8.1+ 必须使用
mongodb扩展 1.15.0+,否则hyperf/mongodb启动时会报Class "MongoDB\Driver\Manager" not found - Swoole 5.x 下需禁用
hook_flags中的SWOOLE_HOOK_CURL(该扩展内部用 curl 做部分元数据请求,与协程 curl 冲突) - 运行
composer require hyperf/mongodb后,必须手动在config/autoload/dependencies.php中注册Hyperf\MongoDB\Pool\ConnectionPool到容器,否则 DI 无法解析
配置连接池和数据库名时注意作用域隔离
hyperf/mongodb 的连接池是按「数据库名」隔离的,不是按「连接字符串」。也就是说,mongodb://a:27017 和 mongodb://b:27017 若共用同一个 database 名(如都配成 test),会共享同一组连接——这在多租户或分库场景下极易引发数据错乱。
- 配置路径为
config/autoload/mongodb.php,每个pool下必须显式声明'database' => 'xxx' - 若需连接多个物理集群,应定义多个独立 pool(如
'user_pool','log_pool'),并在dependencies.php中分别绑定对应ConnectionPool -
options中不要设connectTimeoutMS小于 5000,Swoole 协程环境下过短会导致偶发连接失败且无重试
使用 MongoDB\Collection 时绕过模型层直连更可控
扩展自带的 Model 类(Hyperf\MongoDB\Model)仅提供基础 CRUD,不支持关系预加载、全局作用域、批量 upsert 等高级操作。面对海量写入(如日志归档、IoT 数据流),建议跳过 Model,直接操作 Collection 实例:
// 从连接池获取 Collection,非 new 实例
$collection = $this->container->get(ConnectionPool::class)->getCollection('logs');
// 批量插入:注意 batchSize 默认 100,超大会触发内存溢出
$result = $collection->insertMany($documents, ['batchSize' => 50]);
// 时间范围查询:务必确保字段建了 TTL 索引,否则全表扫描会拖垮整个 MongoDB 进程
$collection->createIndex(['created_at' => 1], ['expireAfterSeconds' => 2592000]);
-
insertMany不会自动处理ObjectId生成,需提前用new \MongoDB\BSON\ObjectId()补全_id - 聚合管道(
aggregate)中避免使用$lookup跨库关联,Hyperf 的连接池不维护跨库 session 上下文,容易超时 - 所有写操作默认是
w:1,高吞吐场景下可改用writeConcern: ['w' => 0](但需接受可能丢数据)
协程安全边界:不能在 defer / onFinish 回调里用 MongoDB 客户端
hyperf/mongodb 的连接对象(Manager 及其衍生 Collection)不是协程安全的——它内部持有的 libmongoc 连接句柄是线程绑定的。一旦你在 go 协程外的生命周期钩子(如 Swoole\Server::onFinish)中调用,会出现段错误或静默失败。
- 正确做法:所有 MongoDB 操作必须包裹在
go协程内,或放在handle()、invoke()等框架明确调度的协程上下文中 - 临时方案:若必须异步落库(如记录请求耗时),先将数据写入 Redis 队列,再由单独的
WorkerProcess消费并同步写 MongoDB - 监控时注意
hyperf/mongodb不上报慢查询,需自行在Collection操作前后打点计算耗时
真正麻烦的不是连接配通,而是当单集合文档量破亿后,countDocuments 会退化成全索引扫描,这时候连 explain 都查不出来——得靠 collStats + count 字段估算,而这个值在分片集群上还不准。











