C # Driver SafeMode отключен Upserts - не все записи обновлены / вставлены - PullRequest
4 голосов
/ 15 октября 2011

В нашем приложении мы выполняем большое количество вставок / обновлений (от 1 до 100 КБ), и я заметил, что не все записи сохраняются.Сохраняет от 90% до 95% записей при отключенном безопасном режиме.

Успешное выполнение upset с safemode для всех записей успешно, но слишком медленно.Я помню, как читал где-то, что даже при отключенном безопасном режиме не должно быть никаких причин, по которым обновление / вставка не должны завершаться ошибкой, если сервер недоступен.

Я написал небольшое приложение для проверки этого и включил приведенный ниже код.Он пытается вставить 100 000 вставок в Mongo, и после проверки после запуска я вижу около 90 000 записей в коллекции.

(Примечание: я использую параллельное обновление, так как я обновляю с помощью _id, а Mongo 2.0 поддерживает параллельные операции при использовании _id. Когда не используется Parallel.Foreach, я все еще вижу некоторую потерю записей, хотя и не такую ​​большую)

        MongoServer server = MongoServer.Create(host);

        MongoDatabase test = server.GetDatabase("testDB");

        var list = Enumerable.Range(0, 100000).ToList();

        using (server.RequestStart(test))
        {
            MongoCollection coll = test.GetCollection("testCollection");

            Parallel.ForEach(list, i =>
            {
                var query = new QueryDocument("_id", i);
                coll.Update(query, Update.Set("value",100), 
                             UpdateFlags.Upsert, SafeMode.False);;
            });
        }

Итак, я думаю, что мой вопрос: каков наилучший способ сделать большое количество обновлений быстро, со 100% вероятностью успеха?

Я не могу использовать вставку, потому что у меня естьчисло процессов, пишущих в Mongo, и я не могу быть уверен, существует ли определенный документ или нет, поэтому я использую Upsert.

Ответы [ 4 ]

7 голосов
/ 21 октября 2011

Когда вы используете SafeMode.False, драйвер C # просто записывает сообщения вставки / обновления в сокет и не ждет ответа. Когда вы очень быстро записываете много данных в сокет, они будут буферизованы на стороне клиента, и сетевой стек будет вытеснять байты из сети так быстро, как только сможет. Если вы насыщаете сеть, все может быть скопировано.

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

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

Однако, если какая-либо из вставок не удалась по какой-либо причине (например, нарушил уникальный индекс), счетчик никогда не достигнет ожидаемого значения. Не существует 100% -ного способа узнать, работает ли вставка / обновление без использования SafeMode.True.

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

2 голосов
/ 19 октября 2011

Я нашел ваш вопрос очень интересным, поэтому я провел некоторое собственное тестирование.

Кажется, что периодически вызывая функцию coll.Count (), я добился успеха в моих тестах.

Вам нужно будет еще тестировать производительность, но я думаю, что это все же лучше, чем делать SafeMode.True

Вот код тестового модуля для подтверждения исправления:

    [TestMethod]
    public void TestMethod1()
    {
        MongoServer server = MongoServer.Create(ConfigurationManager.ConnectionStrings["MongoUnitTestConnStr"].ConnectionString);

        MongoDatabase test = server.GetDatabase("unit_test_db");

        int totalDocuments = 100000;
        var list = Enumerable.Range(0, totalDocuments).ToList();

        int count = 0;
        DateTime start, end;

        using (server.RequestStart(test))
        {
            MongoCollection coll = test.GetCollection("testCollection");

            start = DateTime.Now;
            Parallel.ForEach(list, i =>
            {

                var query = new QueryDocument("_id", i);
                coll.Update(query, Update.Set("value", 100),
                             UpdateFlags.Upsert, SafeMode.False);

                // Calling a count periodically (but sparsely) seems to do the trick.
                if (i%10000 == 0)
                    count = coll.Count();

            });

            // Call count one last time to report in the test results.
            count = coll.Count();

            end = DateTime.Now;
        }

        Console.WriteLine(String.Format("Execution Time:{0}.  Expected No of docs: {2}, Actual No of docs {3}", (end-start).TotalSeconds, count, totalDocuments));
    }

Результаты теста:

Execution Time:105.8125.812. Expected No of docs: 100000, Actual No of docs 100000

0 голосов
/ 04 декабря 2011

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

Кажется, причина именно в том, что Роберт описал выше, и я решил это с помощью

MongoServer.Disconnect()

прежде чем выйти из процесса.Кажется, это сбрасывает все исходящие данные на сервер перед отключением, и поэтому все мои документы вставляются каждый раз.

Как сказал Роберт, это почти никогда не должно быть проблемой в долго работающих процессах, таких как серверы.

0 голосов
/ 21 октября 2011

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

Из интереса, почему используется RequestStart? Конечно, это повлияет на производительность, а не на распределение нагрузки между пулами соединений? (при условии, что сеть не максимальная)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...