notes icon indicating copy to clipboard operation
notes copied to clipboard

PHP MongoDB 连接池 or PHP MongoDB Connection Pooling

Open lanlin opened this issue 4 years ago • 2 comments

MongoDB 驱动有连接池吗?

MongoDB PHP Driver 本身是没有实现连接池的,这是官方自己说的。

MongoDB 驱动开发团队认为传统的单线程 PHP 程序(FPM 模式)下是不需要连接池的。

所以 mongo-php-driver 理论上本身是不支持多线程 PHP 应用程序的(例如: pthreads、forking)。

那么对于异步 PHP 框架(例如: Amp, ReactPHP, Swoole, Workerman...)等有没有什么 办法 呢?

lanlin avatar Oct 18 '21 04:10 lanlin

MongoDB 驱动原理摘要

根据官方的说法, mongo-php-driver 是基于 libmongoc (就是 MongoDB C Driver, 也叫 libmongoc) 开发的。

该驱动是一个 单线程客户端模式 的驱动,并不是连接池的模式,是 一对一 的连接模式。

也就是说 一个 单线程 libmongoc 客户端对象(mongoc_client_t)只会维持 一个 与 MongoDB 服务端的连接。

关于 ”连接+拓扑持久性“:

PHP 驱动自版本 1.2.0+ 版本开始,采用 “连接+拓扑持久性” 的模式

  1. mongo-php-driver 将依据传递给 MongoDB\Driver\Manager 构造函数的参数来计算出一个哈希值, 并创建一个与该哈希值相对应的持久化客户端连接对象(mongoc_client_t),如果该哈希值对应的连接对象存在, 那么就直接复用这个连接。

  2. 其中 MongoDB\Driver\Manager 对象是不能跨 PHP thread 共享的(详见后面的 特别注意)。 而 Manager 构造参数对应的哈希表和持久化客户端连接对象(mongoc_client_t)都是由 MongoDB 驱动自身管理的, 是与 PHP thread 无关的,可以跨 thread 复用。

  3. mongo-php-driver 将自动忽略参数 $uriOptions$driverOptions 中无法识别的选项, 但是这些额外的选项仍然会被用来计算哈希值。因此你可以传递不同的自定义选项来创建出新的连接对象。

  4. mongo-php-driver 从 1.10.0 开始,增加了 disableClientPersistence 选项来判断创建的连接会不会被持久化 (非持久连接对象在超出作用域范围后会被销毁)。

  5. 被持久化的连接会一直在驱动中保留,直到相应的 MongoDB\Driver\Manager 对象超出作用域范围或是对应的进程结束。

补充说明

可以简单理解为,客户端连接对象(mongoc_client_t)是驱动内部管理的,是跨所有 PHP thread 共享的。

只要哪个 Manager 对象参数命中其中某个哈希,就会取得其关联的某个连接对象(mongoc_client_t)。

也就是说只要 参数相同,不论你创建再多的 Manager 对象,起了再多的 PHP thread,

他们始终都只会拿到同一个客户端连接对象(mongoc_client_t)。

lanlin avatar Apr 19 '22 07:04 lanlin

官方对于异步 PHP 程序的建议

  1. 通过 MongoDB\Driver\Manage 构造函数参数的不同,为每个 thread 创建不同的持久化连接

  2. 通过使用 disableClientPersistence (mongo-php-driver version >= 1.10.0),为每个 thread 创建不同的非持久化连接

  3. 你那么牛逼,你自己写一个驱动呗

特别注意

在异步PHP程序中,千万千万不要跨 thread 使用相同的连接(构造参数一致导致的,或者 fork 等导致)。

因为异步并发操作相同连接,可能会有导致 IO 错误的风险 (例如:读取服务器的响应时顺序错误)。

因此,异步程序中,必须为每个 thread 创建不同的连接!

附录:MongoDB 官方关于驱动原理的详细解答

  1. https://github.com/mongodb/mongo-php-driver/issues/1224
  2. https://www.php.net/manual/en/mongodb.connection-handling.php

吐槽

官方的基本意思就一个,我的 php 驱动就是在 c 驱动上写的,c 驱动没有的就不要指望 php 驱动能有。 我们过去,现在,将来都没有打算实现连接池的想法。你不服?不服你自己写一个呗...

7_7688548

lanlin avatar Apr 19 '22 07:04 lanlin