Скорость обновления Mongo

#php #performance #mongodb

#php #Производительность #mongodb

Вопрос:

У меня есть скрипт, который при запуске в моей локальной системе работает быстро, но при запуске в производственной системе он работает намного медленнее. Я подтвердил с помощью профилировщика PHP, что замедление происходит в методе обновления объекта MongoCollection. Я скопировал программное обеспечение PHP (двоичный файл и модули) из производственной системы в свою локальную систему, чтобы убедиться, что это не связано с различием в компьютере / сети. Запуск производственного программного обеспечения PHP в моей локальной системе также выполняется медленно. Итак, проблема не в компьютере или сети. Поскольку это тот же сценарий, он также не соответствует моему сценарию. Это указывает на одну из трех возможностей:

  • Разница в версии PHP
  • Разница в версии драйвера Mongo
  • Разница в конфигурации

Рассматриваемый скрипт перебирает все записи в коллекции и производит обновление для каждой из них. Для обновления установлена проблема записи в 0, поскольку скорость важнее, чем знание того, что оно было выполнено успешно. Профилировщик PHP перестал предоставлять информацию после вызова update (поскольку update реализован на C). Поэтому я обратился к strace, чтобы посмотреть, могут ли системные вызовы помочь объяснить разницу в скорости. Цикл, в котором выдаются обновления, имеет следующую последовательность вывода в быстрой системе:

 sendto(3, "2022063217properties_2"..., 130, MSG_DONTWAIT, NULL, 0) = 130
write(1, ".", 1)                        = 1
sendto(3, "2022073217properties_2"..., 130, MSG_DONTWAIT, NULL, 0) = 130
write(1, ".", 1)                        = 1
sendto(3, "2022103217properties_2"..., 130, MSG_DONTWAIT, NULL, 0) = 130
write(1, ".", 1)                        = 1
  

Я выводю «.» между каждым обновлением, поэтому у меня есть отзывы, указывающие, как быстро идут обновления. При запуске того же скрипта на более медленном PHP я вижу следующее:

 sendto(3, "357v3247properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1009.nv110"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1)                        = 1
sendto(3, "357w3247properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1201.nw110"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1)                        = 1
sendto(3, "357x3247properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1320.nx110"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1)                        = 1
sendto(3, "357y3247properties_2"..., 239, MSG_DONTWAIT, NULL, 0) = 239
poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 30000) = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "1365.ny110"..., 8192, MSG_DONTWAIT, NULL, NULL) = 49
write(1, ".", 1)                        = 1
  

Обратите внимание, что мы добавили системные вызовы. Похоже, что он проверяет ответ, который для меня указывает, что он не использует write concern 0. Основное различие между двумя установками PHP заключается в том, что быстрая установка использует драйвер 1.4.5, а медленная — 1.5.3.

Я сравнил код обновления для обеих версий. В 1.4.5 кажется, что он просто отправляет сообщение и возвращается. С другой стороны, глядя на 1.5.3, он отправляет сообщение, а затем получает ответ. Я ничего не вижу о том, чтобы пропустить проверку ответа, если условие записи равно 0. Если вы будете следовать коду, который извлекает ответ, вы можете увидеть, где он в конечном итоге вызывает эти два дополнительных системных вызова.

Может ли кто-нибудь, кто понимает это лучше, помочь мне понять, как быстро запустить мой код в производство. При быстрой установке PHP (драйвер mongo 1.4.5) скрипт выполняется всего за 2-3 минуты. В медленной системе (драйвер mongo 1.5.3) я убил его через 30 минут, потому что устал ждать. Кто знает, сколько времени потребовалось бы, чтобы полностью выполнить.

Ответ №1:

(Примечание: обновленный оригинальный ответ после некоторых дополнительных исследований)

Новые команды операции записи, которые появились в версии 2.6 и, следовательно, используются между любым поддерживаемым драйвером (PHP 1.5 ) и сервером MongoDB (2.6 ), означают, что новая семантика операций w=0 записи включена. Это означает, что сервер ожидает завершения операции перед отправкой ответа (то есть единственное различие между w=0 и w=1 заключается в том, что w=0 в нем не указаны сведения об ошибке). Драйвер все еще ожидает этого ответа, прежде чем вернуться из вызова (т. Е. Больше Не запускается и не забывается).

Вы также можете увидеть это в самой оболочке MongoDB, и официальный способ обойти это — использовать новый Bulk API. Хотя я знаю, что драйвер 1.5 вернется к устаревшим операциям записи при подключении к серверу 2.4 и ниже, нет способа принудительно изменить это поведение в драйвере PHP.

Комментарии:

1. Мой код явно устанавливает [‘w’ => 0] при каждом обновлении. На 1.4 это, кажется, работает. На 1.5, похоже, он ожидает ответа.

2. Вы правы, и поскольку это полностью изменило ответ, я переписал его

3. Спасибо за информацию. Грустно видеть, что Mongo сбросил fire и забыл. Я понимаю, почему это не должно быть по умолчанию, но это полезно в тех случаях, когда производительность важнее надежности. Вы упомянули, что консоль также делает это, но я переписал свой скрипт на JavaScript, и он выполняется быстро (с той же общей скоростью, что и драйвер 1.4). Доступен ли массовый API с PHP или мы должны использовать JavaScript в консоли?

4. Спасибо за вашу помощь. Пакетный API позволил мне снова запустить мой скрипт примерно за 2,5 минуты вместо более чем 30 минут.

5. Грустно. Не нашел ни слова об изменениях php.net/manual/ru/mongo.writeconcerns.php . Убил час на проблему, пока не нашел этот пост. 1