Подтвердить что ты не робот

Как ускорить вложения MongoDB/sec?

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

Ограничения: должен обрабатывать около 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();
4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Нужно ли использовать осколки?

Вы не можете очертить собранную коллекцию.

Ответ 3

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

Ответ 4

uhmm.. вы не получите такую ​​большую производительность с одного сервера mongodb.

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

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

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

Ответ 5

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

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

Ответ 6

Запись блокировки на MongoDB является глобальной, но в скобках this "блокировка уровня коллекционирования в ближайшее время".

Нужно ли использовать осколки?

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