我有一个脚本,当我在本地系统上运行时运行很快但在生产系统上运行时运行速度要慢得多。我已经向PHP分析器确认,在MongoCollection对象的update方法中发生了减速。我已经将PHP软件(二进制和模块)从生产系统复制到我的本地系统,以确保它不是由于机器/网络的差异。在我的本地系统上运行生产PHP软件也运行缓慢。所以问题不在于机器或网络。因为它是相同的脚本,所以我的脚本也不是。这指出了三种可能性之一:
有问题的脚本遍历集合中的所有记录并对每个记录进行更新。更新将写入关注设置为0,因为速度比知道它已成功执行更重要。 PHP分析器在调用更新后停止提供信息(因为更新是在C中实现的)。所以我转向strace,看看系统调用是否有助于解释速度的差异。发出更新的循环在快速系统上具有以下strace输出:
sendto(3, "\202\0\0\0\206\0\0\0\0\0\0\0\321\7\0\0\0\0\0\0properties_2"..., 130, MSG_DONTWAIT, NULL, 0) = 130
write(1, ".", 1) = 1
sendto(3, "\202\0\0\0\207\0\0\0\0\0\0\0\321\7\0\0\0\0\0\0properties_2"..., 130, MSG_DONTWAIT, NULL, 0) = 130
write(1, ".", 1) = 1
sendto(3, "\202\0\0\0\210\0\0\0\0\0\0\0\321\7\0\0\0\0\0\0properties_2"..., 130, MSG_DONTWAIT, NULL, 0) = 130
write(1, ".", 1) = 1
我正在输出“。”在每次更新之间,所以我有反馈表明更新的进展速度。在较慢的PHP上运行相同的脚本时,我看到以下内容:
sendto(3, "\357\0\0\0v\0\0\0\0\0\0\0\324\7\0\0\0\0\0\0properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1\0\0\0009\0.\nv\0\0\0\1\0\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1) = 1
sendto(3, "\357\0\0\0w\0\0\0\0\0\0\0\324\7\0\0\0\0\0\0properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1\0\0\0\201\0.\nw\0\0\0\1\0\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1) = 1
sendto(3, "\357\0\0\0x\0\0\0\0\0\0\0\324\7\0\0\0\0\0\0properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1\0\0\0\320\0.\nx\0\0\0\1\0\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1) = 1
sendto(3, "\357\0\0\0y\0\0\0\0\0\0\0\324\7\0\0\0\0\0\0properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1\0\0\0\365\0.\ny\0\0\0\1\0\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1) = 1
请注意,我们已添加系统调用。它看起来正在检查回复哪个表明它没有使用写入关注0.两个PHP安装之间的主要区别是快速使用驱动程序1.4.5而慢速使用1.5.3。
我比较了两个版本的更新代码。在1.4.5 it seems to just send the message and return中。另一方面,看1.5.3 it sends the message then gets a reply。如果写入条件为0,我没有看到跳过检查回复的任何内容。如果您按照提取回复的代码,您可以看到最终调用这两个额外系统调用的位置。
能够更好地理解这一点的人可以帮助我弄清楚如何让我的代码在生产中快速运行。在快速PHP安装(mongo驱动程序1.4.5)上,脚本只需2-3分钟即可执行。在慢速系统(mongo驱动程序1.5.3)上,我在30分钟后将其杀死,因为我厌倦了等待。谁知道完成任务需要多长时间。
答案 0 :(得分:3)
(注意:经过一些额外的研究后更新了原始答案)
2.6中引入的新write operation commands因此在任何支持的驱动程序(PHP 1.5+)和MongoDB服务器(2.6+)之间使用意味着w=0
写入的新语义在玩。这意味着服务器在发送响应之前等待操作完成(即w=0
和w=1
之间的唯一区别是w=0
省略了错误详细信息)。在从呼叫返回之前,驱动程序仍然等待该响应(即不再发射并忘记)。
您也可以在MongoDB shell中看到这一点,其官方方法是使用新的Bulk API。虽然我知道1.5驱动程序在连接到2.4及以下服务器时会回退到传统的写操作,但是无法在PHP驱动程序中强制执行该行为。