Как ускорить вставку MongoDB / сек? - PullRequest
31 голосов
/ 01 сентября 2011

Я пытаюсь увеличить количество вставок в секунду. В настоящее время я получаю около 20 тыс. Вставок в секунду. Моя производительность на самом деле ухудшается, чем больше потоков и процессоров я использую (у меня доступно 16 ядер). В настоящее время 2 потока выполняют в секунду больше, чем 16 потоков на 16-ядерном двухпроцессорном компьютере. Есть идеи, в чем проблема? Это потому, что я использую только один Mongod? Индексация может замедлить процесс? Нужно ли использовать шард? Интересно, есть ли способ осквернить, но также сохранить базу данных закрытой ...

Ограничения : должен обрабатывать около 300 тыс. Вставок в секунду, должен быть самоограничивающимся (ограниченным), должен относительно быстро выполнять запрос

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

#!/usr/bin/perl

use strict;
use warnings;
use threads;
use threads::shared;

use MongoDB;
use Time::HiRes;

my $conn = MongoDB::Connection->new;

my $db = $conn->tutorial;

my $users = $db->users;

my $cmd = Tie::IxHash->new(
    "create"    => "users",
    "capped"    => "boolean::true",
    "max"       => 10000000,
    );

$db->run_command($cmd);

my $idx = Tie::IxHash->new(
    "background"=> "boolean::true",
);
$users->ensure_index($idx);


my $myhash =
    {
        "name"  => "James",
        "age"   => 31,
        #    "likes" => [qw/Danielle biking food games/]
    };

my $j : shared = 0;

my $numthread = 2;  # how many threads to run

my @array;
for (1..100000) {
    push (@array, $myhash);
    $j++;
}

sub thInsert {
    #my @ids = $users->batch_insert(\@array);
    #$users->bulk_insert(\@array);
    $users->batch_insert(\@array);
}

my @threads;

my $timestart = Time::HiRes::time();
push @threads, threads->new(\&thInsert) for 1..$numthread;
$_->join foreach @threads; # wait for all threads to finish
print (($j*$numthread) . "\n");
my $timeend = Time::HiRes::time();

print( (($j*$numthread)/($timeend - $timestart)) . "\n");

$users->drop();
$db->drop();

Ответы [ 6 ]

19 голосов
/ 01 сентября 2011

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

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

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

15 голосов
/ 01 сентября 2011

2 потока в настоящее время производят больше, чем 16 потоков на 16-ядерном двухпроцессорном компьютере.

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

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

Нужно ли использовать шардинг?

Вы не можете шардировать ограниченную коллекцию.

2 голосов
/ 01 сентября 2011

хм .. вы не получите такой высокой производительности от одного сервера mongodb.

0,3M * 60 * 60 * 24 = 26G записей / день, 180G записей / неделя. Я предполагаю, что размер ваших записей составляет около 100 байтов, так что это 2,6 ТБ данных / день. Я не знаю, какое поле (поля) вы используете для индексации, но я сомневаюсь, что оно меньше 10-20 байт, поэтому дневной индекс будет больше 2G, не говоря уже о целой неделе ... индекс не будет вписывается в память, с большим количеством запросов, что является хорошим рецептом для катастрофы.

Вы должны сделать ручное разбиение, разбив данные на основе полей поиска. Это крупная телекомпания, вы должны делать репликацию. Купите много одно / двухядерных машин, вам нужны только ядра для основного (perl?) Сервера.

Кстати, как вы запрашиваете данные? Не могли бы вы использовать хранилище ключей-значений?

2 голосов
/ 01 сентября 2011

Я заметил, что построение индекса после вставки помогает.

1 голос
/ 19 июня 2012

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

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

0 голосов
/ 01 сентября 2011

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

Нужно ли использовать шард?

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

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