Недавно я начал консультироваться и помогать в разработке приложения на Rails, которое использовало MongoDB (с Mongoid в качестве клиента БД) для хранения всех экземпляров своей модели.
Это было прекрасно, пока приложение находилось вна раннем этапе запуска, но, поскольку приложение получало все больше клиентов и, начав нуждаться в все более сложных запросах для отображения надлежащей статистики и другой информации в интерфейсе, мы решили, что единственное жизнеспособное решение - нормализация данных, ивместо этого перейдите к структурированной базе данных.
Итак, мы сейчас находимся в процессе переноса как таблиц, так и данных из MongoDB (с Mongoid в качестве объект-сопоставителя) в Postgres (с ActiveRecord в качестве объект-сопоставителя).Поскольку мы должны убедиться, что в базе данных Mongo нет неправильных ненормализованных данных, мы должны запустить эти миграции данных внутри Rails-land, чтобы убедиться, что проверки, обратные вызовы и проверки работоспособности выполняются.
В разработке все прошло нормально, но сейчас мы выполняем миграцию на промежуточный сервер с реальной производственной базой данных.Оказывается, что для некоторых миграций использование памяти сервером линейно возрастает с увеличением количества экземпляров модели, что приводит к прекращению миграции после заполнения 16 ГБ ОЗУ (и еще 16 ГБ подкачки ...).
Поскольку мы переносим экземпляры модели один за другим, мы надеемся найти способ убедиться, что использование памяти может оставаться (почти) постоянным.
Вещи, которые в настоящее время приходят кпомните, что это может быть вызвано тем, что: (a) ActiveRecord или Mongoid хранят ссылки на экземпляры объектов, которые мы уже импортировали, и (б) миграция выполняется в одной транзакции БД, поэтому Postgres занимает все больше и больше памяти, пока она не будет завершена?
Итак, мой вопрос:
- Какова вероятная причина такого линейного использования памяти?
- Как мы можем уменьшить его?
- Существуют ли способы заставить Mongoid и / или ActiveRecord отказаться от старых ссылок?
- Должны ли мы попытаться вызвать Ruby GC вручную?
- Существуют ли способы разделения миграции данных на несколько транзакций БД, и это поможет?
Эти миграции данных имеют следующий формат:
class MigrateSomeThing < ActiveRecord::Migration[5.2]
def up
Mongodb::ModelName.all.each do |old_thing| # Mongoid's #.all.each works with batches, see /5883080/poisk-zapisei-mongodb-v-paketnom-rezhime-s-ispolzovaniem-adaptera-mongoid-ruby
create_thing(old_thing, Postgres::ModelName.new)
end
raise "Not all rows could be imported" if MongoDB::ModelName.count != Postgres::ModelName.count
end
def down
Postgres::ModelName.delete_all
end
def create_thing(old_thing, new_thing)
attrs = old_thing.attributes
# ... maybe alter the attributes slightly to fit Postgres depending on the thing.
new_thing.attributes = attrs
new_thing.save!
end
end