Обновление элементов в базе данных Mongo с одной на несколько машин - PullRequest
0 голосов
/ 10 января 2012

У меня есть вопрос о том, какова лучшая стратегия обновления определенного поля каждого элемента в коллекции mongodb? У меня в коллекции около 3 миллионов предметов, и вся БД находится на одной машине и НЕТ шардинга.

Очевидно, что можно получить курсор для коллекции и пройтись по каждому элементу и обновить желаемое поле одно за другим, но это не кажется эффективным. Это еще сложнее сделать, когда вы хотите выполнить обновление на нескольких машинах, чтобы ускорить процесс, и у вас всегда есть задача обновить те же самые элементы снова. Я должен отметить, что для каждого обновления базы данных моей базы данных требуется HTTP-вызов в Интернет, и если я могу одновременно выполнять несколько обновлений полей, это более эффективно.

Как мне сделать такую ​​вещь?

Я использую драйвер C #.

Примечание: Я не хочу обновлять все поля своих товаров одним конкретным значением. В моем сценарии каждый мой элемент получает различное значение для требуемого поля, и новое значение рассчитывается исключительно для этого элемента. Другими словами, мне, вероятно, все еще нужно получить каждый элемент и использовать мою логику для обновления до нового значения.

Мне интересно, как я могу сделать это одновременно, чтобы я мог применить логику одновременно ко многим элементам, не обновляя элемент дважды?

Я хочу иметь возможность сделать это из одного процесса в нескольких потоках или из другого процесса на нескольких машинах? Это очень напоминает процесс карты в map-Reduce, где map-key - это идентификатор объекта, а map-value - элемент обновления, а преобразователь - это преобразователь идентификаторов, но я не уверен, подходит ли карта / уменьшение MongoDb для такая вещь.

Ответы [ 2 ]

1 голос
/ 10 января 2012

Сложная ситуация, но этот подход, вероятно, самый ресурсоэффективный

  1. "найти" пакет (скажем, 1000) документов для обновления, которые в данный момент не "выполняются", и получить их значения _id.
  2. Запустите многократное обновление в этом пакете, чтобы пометить их как «выполняемые» с безопасной записью = 100 *
  3. Если резервирование выполнено успешно, выполнить логику для всех пакетных документов
  4. Упорядочить пакет по новому значению поля (то есть составить списки всех документов, которые будут иметь одинаковое значение поля)
  5. Для каждого уникального значения поля выполните HTTP-запрос и пакетное обновление, которое устанавливает новое значение поля и либо удаляет флаг «в процессе», либо устанавливает флаг «обработано» в зависимости от ваших функциональных требований.

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

Все, что говорит истинный параллелизм записи, происходит от шардинга и шардинга в одиночку. Ничто не мешает вам запустить 6 mongod-демонов на одной (быстрой) машине. Кроме того, необходимость выполнения HTTP-запроса на обновление значения поля звучит как нечто крайне неэффективное. Нет никакого способа, которым монго пишет (одновременный или иначе) когда-либо был бы узким местом. Если HTTP-запрос направлен на ваш собственный веб-сервис, попробуйте разрешить массовые запросы. Наконец, этот сценарий может быть результатом проблемы схемы. Возможно, вы могли бы сделать поля, которые вы обновляете сейчас, ссылками на меньший набор документов. Если вы предоставите больше контекста, я смогу кое-что выяснить для вас.

0 голосов
/ 10 января 2012

Примерно так должно работать в C #, но я не могу сам это проверить:

var update = Update.Set("field", "new value");
collection.Update(new BsonDocument(), update, UpdateFlags.Multi, SafeMode.True);

Кроме того, вы можете рассмотреть возможность запуска этого обновления из оболочки сервера, что, вероятно, будет быстрее. Это я смог проверить. Потребовалось около минуты, чтобы обновить миллион (очень простых) документов новым полем. Потребовалось около 10 секунд, чтобы снова обновить эти миллионы документов с другим значением того же размера (поскольку не нужно было что-то реорганизовывать).

// where {} searches for all documents,
// {$set : {"field":"new value"}} specifies the field and value to update
// false is for "upsert" behavior
// true is for multi update, updates all matching documents
db.collection.update({}, {$set : {"field":"new value"}}, false, true);
...