У меня есть приложение на C ++, которое обрабатывает JSON и вставляет в БД. Он выполняет довольно простую вставку, анализирует JSON, добавляет пару полей и вставляет, как показано ниже.
Я также окружил вызов try / catch для обработки любых исключений, которые могут быть сгенерированы.
Приложение, вероятно, обрабатывает около 360-400 записей в минуту.
Работает довольно хорошо, но иногда дает ошибки и сбои. Код и трассировка стека ниже.
Код
try {
bsoncxx::builder::basic::document builder;
builder.append(bsoncxx::builder::basic::concatenate(bsoncxx::from_json(jsonString)));
builder.append(bsoncxx::builder::basic::kvp(std::string("created"), bsoncxx::types::b_date(std::chrono::system_clock::now())));
bsoncxx::document::value doc = builder.extract();
bsoncxx::stdx::optional<mongocxx::result::insert_one> result = m_client[m_dbName][std::string("Data")].insert_one(doc.view());
if (!result) {
m_log->warn(std::string("Insert failed."), label);
}
} catch (...) {
m_log->warn(std::string("Insert failed and threw exception."), label);
}
Stack
Так что, думаю, у меня есть два вопроса. Любые идеи относительно того, почему это терпит крах? И есть ли какой-нибудь способ, которым я могу перехватить и обработать эту ошибку таким образом, чтобы она приводила к аварийному завершению приложения.
mongocxx версия: 3.3.0
Mongo-C версия: 1.12.0
Любая помощь приветствуется.
Обновление 1
Я выполнил некоторое профилирование БД, и, несмотря на то, что он выполняет большое количество операций записи, работает достаточно хорошо, и все операции используют индексы. Самая неэффективная операция занимает 120 мс, поэтому я не думаю, что это является проблемой производительности с этой стороны.
Обновление 2
После профилирования с помощью valgrind я не смог найти ошибок размещения. Затем я использовал perf для профилирования загрузки процессора и обнаружил, что со временем загрузка процессора увеличивается. Обычно начинается примерно с 15% базовой нагрузки при первом запуске процесса, а затем наращивается в течение 4 или 5 часов до тех пор, пока не произойдет сбой с использованием ЦП около 40-50%. В течение всего этого времени число операций с БД в секунду остается постоянным и составляет 10 в секунду.
Чтобы исключить возможность другого кода обработки, вызывающего это, я удалил всю обработку БД и запустил процесс в течение ночи, а загрузка ЦП оставалась неизменной на уровне 15% все время.
Я пробую несколько других стратегий, чтобы попытаться определить причину сейчас. Обновлюсь, если найду что-нибудь.
Обновление 3
Я считаю, что я обнаружил причину этой проблемы. После процесса вставки также происходит обновление, которое помещает два элемента в массив с помощью оператора $ push. Он делает это для разных записей до 18 000 раз, прежде чем этот документ будет закрыт. Тот факт, что он падал на вставке при высокой загрузке процессора, был чем-то вроде красной селедки.
Процесс использования ЦП состоит в том, что процессу требуется больше времени для выполнения, так как массив в документе, на который проталкивается, становится длиннее. Я перепроектировал использование Redis и вставлял в mongodb только после получения всех элементов, которые нужно вставить в массив. Это плоское использование процессора. Другим способом решения этой проблемы может быть вставка каждого элемента во временную коллекцию и использование агрегации с $ push для компиляции одной записи с массивом после получения всех элементов, которые нужно отправить.
Графики ниже иллюстрируют проблему с использованием $ push для документа, поскольку массив становится длиннее. Огромные капли возникают, когда все записи получены и созданы новые документы для следующего набора элементов.
Закрывая эту проблему, я посмотрю на MongoDB Jira и выясню, сообщал ли кто-нибудь об этой проблеме с помощью оператора $ push, а если нет, то сам сообщал об этом, если это что-то может быть улучшено в будущих выпусках.