db driver.php,MongoDB php driver 简要分析

关于连接、连接池、长连接、短连接 连接池。PHP MongoDB driver 版本( 1.2.0-1.2.12 only )使用连接池(Connection Pooling) 1.1.4及之前版本可以选择使用短连接或者长连接 举个简单的例子,写段程序连接1000次数据库: ?phpfor ($i=0; $i 需要将近18秒; 使

关于连接、连接池、长连接、短连接

连接池。PHP MongoDB driver 版本( 1.2.0-1.2.12 only)使用连接池(Connection Pooling)

1.1.4及之前版本可以选择使用短连接或者长连接

举个简单的例子,写段程序连接1000次数据库:

for ($i=0; $i

需要将近18秒;

使用长连接

for ($i=0; $i "x"));

}

?>

小于0.02秒。

1.2.x 使用连接池,所有连接都是长连接,驱动自动管理。使用长连接的直接原因是效率高。因为连接复用而省去了大量的创建连接的开销。长连接由PHP进程维护。

在执行任何查询时,都会从连接池中请求一个连接,完成之后再归还给连接池。这里的完成是指持有该连接的变量离开了它的作用域。

1.3以后连接管理做了很大改动,抛弃了连接池,连接均为长连接。

每个worker进程(线程、PHP-FPM或Apache worker)中,驱动把连接管理和Mongo*对象分离,降低驱动的复杂度

当一个worker进程启动,MongoDB驱动会为之初始化连接管理器管理连接,并且默认没有连接。

在第一个请求调用new MongoClient();时,驱动创建一个新连接,并且以一个哈希值标识这个连接。

这个哈希值包括以下参数:主机名、端口,进程ID和可选的replica set名,

如果是密码验证的连接,则还包括数据库名、用户名和密码的哈希值(对于密码验证的连接,我们后面再详细讨论)。

调用MongoClient::getConnections()方法,可以查看连接对应的哈希值

然后该连接会在连接管理器中注册:

在需要连接的任何时候,包括插入、删除、更新、查找或执行命令,驱动都会向管理器请求一个合适的连接来执行。

请求连接时会用到new MongoClient()的参数和当前进程的ID。每个worker进程/线程,连接管理器都会有一个连接列表,

而每个PHP worker同一时刻,只会运行一个请求,因此和每个MongoDB之间只需要一个连接,不断重用,

直到PHP worker终止或显式调用MongoClient::close()关闭连接。

源码简要分析,版本mongo-php-driver-1.4.5

连接初始化及连接管理

连接管理器(manager)初始化:

模块初始化的时候也就是在PHP_GINIT_FUNCTION()里面,初始化连接管理器。

php_mongo.c L288 mongo_globals->manager = mongo_init(); mongo_init()定义在mcon/manager.c L622

mongo_init() 初始化建立连接(socket连接)。

连接管理器与MongoClient分离,下面看MongoClient初始化:

mongoclient.c L338

PHP_METHOD(MongoClient, __construct)

{

php_mongo_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);

}

php_mongo_ctor主要工作:

指定连接管理器为上面的全局管理器;

解析连接的一些参数设置,如主机,端口,选项w等等,

调用php_mongo_connect()函数

php_mongo_connect()函数定义在mongoclient.c L275

php_mongo_connect()主要调用mongo_get_read_write_connection()函数(mcon/manager.c L415)

来获得合适的连接;

mongo_get_read_write_connection()主要工作是获得合适的连接:

根据单机、复制集、mongos以及不同读写分离设置获取到合适的连接

代码对应

STANDALONE 调用mongo_get_connection_multiple(定义mcon/manager.c L319)

REPLSET mongo_get_read_write_connection_replicaset()(mcon/manager.c L249)

multiple(mongos类型在这里处理) mongo_get_connection_multiple()

获取连接及读写分离

在mcon/parse.c L457 处理replicaSet选项

L483 设置了servers->options.con_type = MONGO_CON_TYPE_REPLSET

MongoClient的__construct()和connect()里面会调用php_mongo_connect()函数

php_mongo_connect()函数定义在mongoclient.c L275

在mongo_connection()里面调用mongo_get_read_write_connection()函数

mongo_get_read_write_connection()函数定义在mcon/manager.c L415

在mongo_get_read_write_connection()里面判断了servers->options.con_type

对于replica sets,调用mongo_get_read_write_connection_replicaset()

mongo_get_read_write_connection_replicaset()定义在mcon/manager.c L249

在mongo_get_read_write_connection_replicaset()里面调用了mongo_discover_topology()去探测服务器

mongo_discover_topology()的实现在mcon/manager.c L144 ,

mongo_discover_topology()->mongo_connection_ismaster(mcon/manager.c L167)

->bson_create_ismaster_packet(mcon/mini_bson.c L86)->执行isMaster命令

replica sets

根据read preference设置,查出候选servers.

调用mongo_find_candidate_servers(mcon/read_preference.c L319)

调用mongo_find_all_candidate_servers (mcon/read_preference.c L135)

PRIMARY 找PRIMARY

PRIMARY_PREFERRED 不处理

SECONDARY_PREFERRED 找PRIMARY和SECONDARY

SECONDARY 只找SECONDARY

NEAREST 找所有类型

调用mongo_filter_candidates_by_replicaset_name(mcon/read_preference.c L211),根据复制集名称过滤;

调用mongo_filter_candidates_by_credentials (mcon/read_preference.c L270) 根据db,username,password认证,通过验证的添加到候选连接里。

调用mongo_sort_servers (mcon/read_preference.c L424)根据read preference的几种设置选项对于的排序算法,基本都是按照 ping time来排序。

调用mongo_select_nearest_servers(mcon/read_preference.c L461),

如果read preference设置的是PRIMARY,PRIMARY_PREFERRED,SECONDARY,SECONDARY_PREFERRED,NEAREST;

选择ping值最低的作为第一个元素,距最低的ping值15ms内的成员都添加进去。

调用mongo_pick_server_from_set (mcon/read_preference.c L510)

PRIMARY_PREFERRED,

根据上面的排序选择结果,如果第一个是PRIMARY(一般是),选择PRIMARY,

(当然选择如果第一个不是PRIMARY,即无主的情况,进入下面的随机选择(rand()),随机选一个复制集成员;

SECONDARY_PREFERRED,

根据上面的排序选择结果,如果大于1个,如果最后一个是PRIMARY,随机选择除PRIMARY之外SECONDARY的成员;

(当然如果只有1个了,跳到下面的随机选择步骤,选择的是PRIMARY)

随机选择,这里不管read preference设置,包含SECONDARY和nearest,

SECONDARY和nearest区别是nearest把PRIMARY当做其他secondaries一样。

nearest不是选择ping值绝对最低的那一个,而是包含绝对最低的+15ms内的组合里(如果到这个阶段不止一个的话)随机选择一个。

mongos

调用mongo_get_connection_multiple(mcon/manager.c L319)

调用mongo_get_connection_single( mcon/manager.c L55),测试连通性

调用mongo_find_candidate_servers (mcon/read_preference.c L319)->

调用mongo_filter_candidates_by_seed ( mcon/read_preference.c L245 ) 连接生成hash,

比较seed列表里hash与servers里的hash,返回相等的。

调用mongo_filter_candidates_by_credentials (mcon/read_preference.c L270) 根据db,username,password认证

通过验证的添加到候选连接里。

调用mongo_sort_servers (mcon/read_preference.c L424)根据read preference的几种设置选项对于的排序算法,基本都是按照

ping time来排序。

调用mongo_select_nearest_servers(mcon/read_preference.c L461),选择ping值最低的。

Hash格式:

HOST:PORT;-;.;PID

或者

HOST:PORT;REPLSETNAME;DB/USERNAME/md5(PID,PASSWORD,USERNAME);PID

简单总结

对给出的mongos连接串,逐个去建立连接,测试连通性,如果都连不通,退出;

对这些连接做一下过滤与验证,对合格的连接根据ping值选择最快的来连接。

所以对于mongos来说,如果只提供一个连接,是不能找到其他mongos的。这与replica sets不同,

对于replica sets,任意一个数据成员可以找到其他所有数据成员。

参考:

http://mongodb.github.io/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html

http://emptysqua.re/blog/reading-from-mongodb-replica-sets-with-pymongo/

http://docs.mongodb.org/manual/core/read-preference-mechanics/

http://wulijun.github.io/2012/12/10/mongodb-php-driver-connectiong-handling.html

http://derickrethans.nl/mongodb-connection-handling.html

http://www.php.net/manual/zh/mongo.connecting.persistent.php

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值