2013-09-04 9 views
0

При выполнении медленного запроса мы сталкиваемся с полу-странным поведением в PHP-драйвере MongoDB (v1.3). Водитель, похоже, продолжает открывать соединения, когда запросы медленные, и я не совсем понимаю, почему. Может быть, у вас есть несколько предложений здесь.PHP MongoDB драйвер открывает множество соединений при медленном запросе

Вот некоторые факты: первые

  • Сайт и запуск базы данных на одном сервере Ubuntu 13.04
  • сервер является высоким класс 8 основных сервера 16GB RAM
  • MongoDB v2.2.4
  • проходит на сайте PHP 5.4
  • Apache 2 как веб-сервер
  • PHP Mongo driver 1.3.x (должен быть самым новым 1.3)
  • Сайт использует Doctrine ODM
  • Сайт имеет около 50 до 100 одновременных пользователей в любой момент
  • ULIMIT открытые файлы (ULIMIT nofile) = 64000

Раз в день записи Memcache истекает и медленный запрос сделанный. Это приводит к тому, что PHP открывает до 800 соединений с MongoDB (обычно у нас есть 10 открытых подключений по журналам). Наш сайт почти полностью Memcached, поэтому наша база данных не имеет каких-либо других значительных нагрузок. В 800 открытых соединениях веб-сайт имеет 30 секунд загрузки в начале и бросает несколько типов MongoExceptions (слишком много соединений/исключений сокетов) позже.

Это уродливый запрос с группой. Чтобы быть совершенно ясным, мы понимаем, что этот запрос медленный и идиотский, и мы удаляем этот запрос сегодня. Просто непонятно, почему он закручивает весь сайт. Мы используем Учение, как уровень абстракции, но это реальный запрос в базе данных 200 000 документов (3 полей в документе: идентификатор/продукта/дата)) в соответствии с бревнами:

{"group":true,"keys":{"product":1},"initial":{"count":0},"reduce":"function (obj, prev) { prev.count++; }","options":[],"db":"Orders","collection":"History"}

После запроса его результаты записываются в Memcache в течение 24 часов. Таким образом, все новые запросы получают его от Memcache, а не от MongoDB. Но, тем не менее, он поддерживает около 800 соединений, проблема не решается сама собой, и через некоторое время веб-сайт больше не отвечает. Эти 800 соединений занимают около 10 минут.

Это похоже на типичное состояние гонки. Запрос просто не чувствует себя достаточно тяжелым, чтобы фактически вызвать состояние гонки на этом сервере с этой нагрузкой. Я имею в виду, похоже, что этого не должно быть.

Хорошо, поэтому вопросы:

  1. Почему PHP держать отверстие так много соединений?
  2. Почему MongoDB не может справиться с этим (это не должно быть ЧТОБЫ большая проблема, не так ли?)
  3. Любые другие предложения о том, что мы должны делать?
  4. Должен ли я устанавливать таймауты на соединениях и запросах, чтобы решить это, или это что-то еще?

Причина, по которой я спрашиваю об этом, потому что наш сайт растет очень быстро, и мы ожидаем, что больше трафика и нагрузки MongoDB в будущем.

Большое спасибо!

ответ

1

Учитывая, что вы вызываете команду group вместо выполнения базового запроса на чтение, вы также можете бороться с интерпретатором JavaScript в MongoDB 2.2. Только до тех пор, пока 2.4 не будет усовершенствован, чтобы интерпретатор JavaScript был расширен для поддержки одновременного выполнения. Если для каждой из этих групповых операций требуется оценка JS (по крайней мере, для функции reduce), вы смотрите на широко распространенный ресурсный голод.

У меня нет объяснений исключений «слишком много соединений». Даже 800 одновременных подключений значительно упали ниже предела MongoDB в 20 000 (обратите внимание: это удаляется для 2.6 в SERVER-8943).

Одна из идей, чтобы реорганизовать ваше приложение и избежать состояния гонки group, состояла в том, чтобы использовать один документ в качестве блокировки для процесса PHP, чтобы перекомпилировать результат и пополнить кеш. Используя findAndModify, у вас может быть один документ с некоторой строкой _id (например, «Order.History group») и еще одно поле active. Когда процесс PHP получает пропущенную кэш-память и ему нужно будет пересчитать результат, он может сначала попытаться выполнить findAndModify и найти подходящий _id, где active - false, обновление active до true в том же атомном режиме. Только после получения этого документа блокировки, если он продолжит команду group. Другие PHP-процессы, которые не могут найти документ блокировки (потому что active не будет false), может быть предложено немного поспать, вернуть устаревшие данные или прервать веб-запрос.