如何加速MongoDB Inserts / sec?

时间:2011-09-01 01:07:55

标签: perl mongodb

我正在尝试每秒最大化插入次数。我目前获得大约20k插入/秒。我的性能实际上降低了我使用的线程和CPU的数量(我有16个核心可用)。目前,2个线程比16核双处理器机器上的16个线程每秒更多。关于问题是什么的任何想法?是因为我只使用一个mongod吗?索引可能会减慢速度吗?我需要使用分片吗?我想知道是否有办法分片,但也保持数据库上限...

约束:必须处理大约300k插入/秒,必须是自我限制(上限),必须能够相对快速地查询

问题空间:必须处理主要手机公司的通话记录(大约300k插入/秒),并尽可能长时间地查询这些通话记录(例如,一周)< / p>

#!/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 个答案:

答案 0 :(得分:19)

写入MongoDB目前获取全局写锁定,尽管collection level locking有望很快到来。通过使用更多线程,您可能会引入更多并发问题,因为线程在等待释放锁时会相互阻塞。

索引也会降低你的速度,以获得最佳的插入性能,这是在加载数据后添加它们的理想选择,但这并非总是可行,例如,如果你使用的是唯一索引。

要真正最大化写入性能,最好的选择是分片。当您在多台计算机上分配写入时,这将为您提供更好的并发性和更高的磁盘I / O容量。

答案 1 :(得分:15)

  

当前2个线程每秒比16核双处理器机器上的16个线程更多。

MongoDB inserts cannot be done concurrently。每个插入都需要获取写锁。不确定这是全局锁定还是每个集合锁定,但在您的情况下不会产生任何影响。

因此,一旦Mongo成为瓶颈,使这个程序成为多线程并没有多大意义。

  

我是否需要使用分片?

您无法对上限集合进行分片。

答案 2 :(得分:2)

我注意到插入帮助后构建索引。

答案 3 :(得分:2)

嗯......你不会从一台mongodb服务器那里得到那么多的性能。

0.3M * 60 * 60 * 24 = 26G记录/天,180G记录/周。 我猜您的记录大小约为100字节,因此每天的数据为2.6TB。我不知道你用什么字段进行索引但是我怀疑它低于10-20字节,所以只是每日索引将超过2G,更不用说整周......索引不会适合内存,有很多查询,这是一个很好的灾难配方。

您应该执行手动分片,根据搜索字段对数据进行分区。这是一家主要的电话公司,你应该做复制。购买很多单核/双核机器,你只需要主(perl?)服务器的核心。

BTW你如何查询数据?你能使用键值存储吗?

答案 4 :(得分:1)

为什么不手动上限?您可以在多台计算机上进行分片并应用查询所需的索引,然后每隔一小时左右删除不需要的文档。

你遇到的瓶颈很可能是全局锁定 - 我在MongoDB评估插件繁重的时间序列数据应用程序时看到了这种情况。您需要确保分片键不是时间戳,否则所有插入将在同一台机器上顺序执行,而不是分布在多台机器上。

答案 5 :(得分:0)

MongoDB上的写锁定是全局的,但即将引用this“集合级锁定”。

  

我是否需要使用分片?

回答并不容易。如果你可以从一个 mongod 中获得的东西不能满足你的要求,你就必须这样做,因为分片是在MongoDB上扩展写入的唯一方法(不同实例上的写入不会相互阻塞)。