Преобразование данных из Mongo в MySQL (110M docs, 60Gigs) - Советы и предложения?

Мне поручили переносить данные из базы данных MongoDB в базу данных MySQL. (Есть серьезные причины для переноса - так что это нужно сделать).

Коллекция MongoDB:

  • Имеет около 110 миллионов документов
  • Весит 60 ГБ.
  • Имеет индексы для важных свойств
  • Выполняется автономный отдельный сервер Windows 2008, который не обслуживает какой-либо производственный трафик.

Программа, которую мы пробовали:

  • Экзамен большого экземпляра Amazon EC2 Win2008 с 7,5 гигабайтами оперативной памяти /8 записей файла страницы.
  • Консольное приложение С#, которое преобразует данные MongoDB в локальную базу данных MySQL.

Мы собираем 1K документов за раз в памяти от MongoDB, выполняем необходимую обработку и затем сохраняем их в MySQL db, делая периодические записи по 500 за раз.

Проблема, с которой мы сталкиваемся, заключается в том, что каждый 2.5 M docs, сервер задыхается, и Mongo реагирует очень медленно - сглаживает операцию извлечения данных приложения (Free RAM переходит на время обработки документов 1M)

Мы медленно продвигаемся вперед, убивая процесс mongod и начинаем его снова каждые 2.5M записи, когда он падает, но я уверен, что мы делаем что-то неправильно.

Вопрос:

Должен ли я переместить Mongo Server на большой экземпляр на базе Linux и MySQL на Amazon RDS для этого и переписать приложение преобразования в PHP? Помогло ли это?

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

Какие еще вещи я могу попробовать/советы, которые я могу использовать?

Спасибо, что прочел это!

- Обновление 01 -

Он был приблизительно 6 часов с момента перезапуска моего приложения и сделал следующее изменение:

  • Увеличенное количество просмотров Mongo Read от 1000 до 10 000 записей за раз. Пропустите (10K).limit(10K)
  • Удалены все индексы из целевой базы данных MySQL.
  • Увеличен размер страницы Windows с 4 до 8 гигов.

Моя память потребляет 100%, но приложение работает. (Последний раз он прохрипел через 52 минуты). Mongo - 6,8 гигабайта оперативной памяти, MySQL - 450 мегабайт и приложение конвертера - 400 мегабайт (приблизительные значения).

Обработано 11M записей до сих пор - но скорость снизилась до 370 записей/сек с примерно 500 записей/сек.

Следующие шаги состоят в том, чтобы изолировать как серверы Mongo, так и MySQL для разделения ящиков и - сохранить все их в той же зоне доступности Amazon, чтобы минимизировать время ожидания.

- Обновить 02 -

Мы внесли некоторые изменения в код, чтобы использовать Mongo Cursor и автоматически увеличивать его автоматически против использования .skip(). limt(). Это значительно ускорило процесс, и мы делали 1250 записей в секунду от 300 нечетных ранее. Тем не менее, приложение начало потреблять слишком много памяти и закончилось бы из ОЗУ и аварийным завершением, и его необходимо было перезапустить после каждых двух записей.

Мы использовали этот фрагмент кода:

var docs = db[collectionName].Find(query);
docs.SetBatchSize(numOfResultsToFetchAtATime);
foreach (var d in docs) {
  // do processing
}

Итак, что это значит, это выборка "numOfResultsToFetchAtATime" за раз, но затем автоматически выполняется в цикле и выбирает следующий набор записей. Монго позаботится об этой прогрессии с помощью курсора, и, следовательно, это намного быстрее.

Однако мы все еще не смогли успешно перенести это. Отправьте мой ответ с кодом, когда это произойдет правильно.

- Обновление 03: Успех -

Наконец, мы использовали предложение @scarpacci о выполнении mongoexport. Помните, что очень важно, чтобы mongodb находился в окне Linux, а не в окне окна.

Сначала мы попробовали сделать mongoexport из Windows на локальном MongoDB и независимо от того, что мы пробовали, он потерпит неудачу в разных местах для одной большой коллекции (13Gigs +)

Наконец, я восстановил БД на Linux-боксе, и mongoexport работал как шарм.

Нет конвертера Json → MySQL, так что многое нам нужно было сделать. С небольшой настройкой мы смогли использовать наше предыдущее приложение и прочитать файлы и напрямую написать MySQL. Это было быстро и относительно безошибочно.

У нас были некоторые проблемы с большими файлами, но с ним удалось разбить 13-гигабайтный файл на 500 мегабайтных файлов, и мы смогли успешно перенести все данные в MySQL.

Большое спасибо всем за то, что они проводят время, помогая нам. Надеюсь, что это объяснение поможет кому-то в будущем.

Ответ 1

Рассматривали ли вы использование mongoexport, а затем выполняли какую-то массовую вставку в MySQl? Не уверен, что это доступно в MySql, но мы все время выполняем что-то подобное в SQL Server. Можете ли сделать свалки/вставки легче разделиться и оптимизировать? Просто мысль....

Ответ 2

У меня возникли проблемы с переносом данных на SQLServer с использованием .NET один раз - хотя я старался держать его как можно более легким, он все же был недопустим медленным. В конце я написал быстрое приложение С++ OLEDB, и все прошло значительно быстрее. Я все еще пытаюсь понять, что я сделал неправильно в своем приложении .NET, но это может быть проблемой в .NET. Я бы не переписал преобразование в PHP, но перейдите с параметром производительности и используйте С++ (возьмите урок из Интернета, его не так сложно, а не для отложенного приложения)

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

Мне интересно, что вы остановили приложение MongoDB, а не что-то еще. Что заставляет вас думать, что его MongoDB умирает, а не другие системы? Если его использование памяти, а затем разделение на отдельные блоки может иметь значение, если его медленно растущая память, то читать меньше кусков - Mongo должно быть хорошо с чтением данных, поэтому, если это не так, скорее всего, это то, что вы сделали с ним закрепите его в своей памяти либо в конфигурации, либо в вашем приложении.

Запустите perfmon и посмотрите на память, свопинг, дисковое IO и использование процессоров Mongo, вашего приложения и экземпляра MySQL.

Ответ 3

Как только я переместил большую базу данных (не 60 ГБ, но достаточно большой, чтобы показать проблемы) Я закончил тем, что написал небольшое приложение, выполняющее эту работу.

Таким образом, я читаю из одной БД и писал другому, с каким-то (я столкнулся с аналогичными проблемами с сбоями базы данных и т.д.)

То, что я сделал, порождает небольшие транзакции для каждой части и закрывая их каждый раз, когда рабочий элемент был решен.

У нас были таблицы в обеих базах данных, без документов, но проблема будет быть одинаковым.

В конце концов:

  • Существует одно приложение, которое координирует перенос, но не имеет никаких связей с базой данных на нем
  • Несколько экземпляров, созданных из приложения для координации, для перемещения данных, выполнения рабочего элемента, закрытия после этого (есть способ сообщить об успехе перед закрытием). Таким образом, вы можете иметь несколько читателей/писателей и экспериментировать со счетом, я только около 10 одновременных экземпляров чтения/записи за один раз. Если ваши документы достаточно малы, вы можете создать много больше. Но все равно они будут очень быстро закрываться.

Примечание.. Не указывайте индексы в целевой базе данных при записи в это даст вам максимальную производительность. Установите индексы когда у вас есть все данные в них.

Ответ 4

Нет причин для того, чтобы вы записывали данные непосредственно в MySQL - разделили задание на два отдельных этапа, и вы будете запускать сначала MongoDB, а затем MySQL, чтобы они не конкурировали за ресурсы - похоже, что растущий MySQL процесс голодает Mongo по RAM или io.

Первый этап: получить данные от MongoDB, обработать его и сохранить в текстовый файл (как SQL). Остановите Mongo, запустите MySQL

Вторая стадия: запуск регулярного импорта базы данных с использованием файла, сгенерированного на этапе 1.

Ответ 5

Тот факт, что перезагрузка MongoDB исправляет проблему с производительностью и постоянное количество записей, которые вы можете обрабатывать до того, как оно появится, звучит как утечка ресурсов для меня. Я бы удостоверился, что все закрыто и т.д. Убедитесь, что MySQL не настроен на использование слишком большого объема памяти или, лучше, переместите его на другую машину.