mongodb 并发性能测试

之前做的一些mongodb的测试都是在exsi的两台虚拟间做的,由于虚拟机的问题,性能很不稳定。这两天正好有两台服务器空下来了,就用来跑了一下mongodb的并发测试。

服务器软硬件配置:

服务器:Dell PowerEdge R710
CPU: Intel Xeon E5530 2.4G X 2
硬盘:SAS 300G X 4 建立 Raid10
内存:16G

windows 2003 sp2 64位
mongodb 1.40 x64 for windows

mongodb在这台上跑,测试程序在另一台服务器上跑,两台服务器配置基本一样,除了硬盘(另一台是SAS 147G X4  Raid10)。

测试程序在之前的java测试程序基础上做了修改,增加了多线性的并发测试功能,程序源代码可从下面的链接下载:

http://farmerluo.googlecode.com/files/mongotest_0.3.rar

程序用法:
Usage:
mysql test:
java -jar mongotest.jar < mysql > < [select | update | insert] > < rows > <concurrent> < host > < username > < password>  <database>
mongo test:
java -jar mongotest.jar < mongo > < [select | update | insert] > < rows > <concurrent> < host > <database>

由于时间关系,mysql没有来得急测试,只测试了mongodb。

后期准备再找机器在linux系统上好好的测一下mongodb和mysql的并发性能(因为我发现虽然mongodb在单用户测试的情况下性能很好,但随着并发用户的增加,性能都是往下掉的,而我跑了一次50个并发的mysql,总的吞吐量反而是往上走的,所以很有必要同时测一次mysql和mongodb的并发性能)。

先看一下测试结果,因为这里不好贴表,只能上图了:

有一点需要说明一下,因为并发数为1的时候,select很慢,跑1000万花的时间过长,所以我这边只测试了10万条记录,我看看了数据,差别并不大。

测试的总记录数都是1000万,可以看到,随着并发数的增加,mongdb的insert吞吐量掉得很快。而update稍为平稳一些,总得也在往下走的,从查询来看,随着并发的增加,吞吐量也跟着增加,符合我们的预期。

insert的时候,mongodb会创建多个数据库文件,他会先创建一个64M的文件,不够用了再创建一个128M,然后是256M,512M,1G,2G,然后就是一直2G的创建下去。

测试程序写入的记录是每条1k多一点(4 X 256字符,再加一个int,一个默认的_id),所以1000万记录算出来差不多是10G(除了默认的索引_id,没有另外加其它索引)。而实际上,mongodb总共创建了147G的数据库文件。这样的存储容量对于想用固定硬盘的用户来说是个考验。

insert并发吞往下掉的原因,我怀疑是因为在多并发时mongodb同时操作IO有关,其实通过mongodb服务器上的监控程序我们看到,在mongodb创建1G的数据库文件之前,每秒insert有20000左右,后来就开始低了。我们知道,当写一个1G文件花的时间,总是要比同时写10个100M的文件来得要快。但是这块我想mongodb还有优化的空间,官网上也承认之前的版本并发性能并不好,所以在1.4版本上做了改进。

200并发时update反而比100并发性能要好,或许和单并发测试的数据比较少有关,在200并发时,单并发只测试了5万数据。

另外在高并发时,mongodb的稳定性和健状性也是非常值得关注的。我们在测试200并发时,跑了一段时间后,从mongodb的监控程序发现突然没有了insert的数据,然而java的测试程序也并没有报错,就一直停在那里不动。重启并做一些优化后才测试完200并发。

资源占用方面:cpu 20%上下,任务管理器内显示PF内存占用1G,但mongod进程显示占用了12G的内存做缓存使用了。

或许看线性图表更为直观一些:

另外也测试了一下大数据量的并发测试

内网测试,100线程,每线程50万记录:

D:dist>java -Xms256M -Xmx1024M -jar mongotest.jar mongo insert 500000 100 192.168.1.12 dbtest
Total thread:100
Total run time:10404 sec
Per-thread rows:500000
Per-thread mongo insert Result:48row/sec
Total rows:50000000
Total mongo insert Result:4805row/sec

D:dist>java -Xms256M -Xmx1024M -jar mongotest.jar mongo update 500000 100 192.168.1.12 dbtest
Total thread:100
Total run time:13103 sec
Per-thread rows:500000
Per-thread mongo update Result:38row/sec
Total rows:50000000
Total mongo update Result:3815row/sec

D:dist>java -Xms256M -Xmx1024M -jar mongotest.jar mongo select 500000 100 192.168.1.12 dbtest
Total thread:100
Total run time:1869 sec
Per-thread rows:500000
Per-thread mongo select Result:267row/sec
Total rows:50000000
Total mongo select Result:26752row/sec

用这个数据对比表中100并发的数据,我们发现,虽然性能也在往下掉,但相比因并发增加而下降的性能来说并不夸张,在预期范围之内。由此可见,mongodb对于大数据量来说性能还是不错的。

mysql与mongodb性能测试java程序更新

对之前写的java测试程序进行了更新,增加了一些参数和查询的测试:

http://farmerluo.googlecode.com/files/mongotest.rar

使用方法:

[root@web dist]# java -jar mongotest.jar
Usage:
mysql test:
java -jar mongotest.jar < mysql > < [select | update | insert] > < rows >  < host > < username > < password>  <database>
mongo test:
java -jar mongotest.jar < mongo > < [select | update | insert] > < rows >  < host > <database>

然后用这个程序测试了1亿条数据的更新和插入:

[root@web dist]# ./run.sh
java -jar mongotest.jar mongo insert 100000000 192.168.20.24 dbtest
Mongo Exception:can’t say something
Mongo error code:-2
Mongo Exception:can’t say something
Mongo error code:-2
Mongo Exception:can’t say something
Mongo error code:-2

Total run time:13670 sec
Total rows:100000000
mongo insert Result:7315row/sec

java -jar mongotest.jar mongo update 100000000 192.168.20.24 dbtest
Total run time:7927 sec
Total rows:100000000
mongo update Result:12615row/sec

java -jar mongotest.jar mongo select 100000000 192.168.20.24 dbtest
Exception in thread "main" java.util.NoSuchElementException
at java.util.LinkedList$ListItr.next(LinkedList.java:698)
at com.mongodb.DBCursor._next(DBCursor.java:335)
at com.mongodb.DBCursor.next(DBCursor.java:413)
at mongotest.mongodb.mongodb_select(mongodb.java:111)
at mongotest.Main.main(Main.java:65)

因为网络问题,有些没有insert成功,只成功了99992390条记录。mongo server上会报这种错误:
Thu Apr  8 19:24:19 insert dbtest.test 159ms
Thu Apr  8 19:24:22 MessagingPort recv() got 1 bytes wanted 4, lft=3
Thu Apr  8 19:24:24 insert dbtest.test 104ms
Thu Apr  8 19:24:30 MessagingPort recv() got 2 bytes wanted 4, lft=2
Thu Apr  8 19:24:36 insert dbtest.test 136ms
Thu Apr  8 19:24:41 insert dbtest.test 130ms
Thu Apr  8 19:24:42 insert dbtest.test 327ms
Thu Apr  8 19:24:43 insert dbtest.test 130ms
Thu Apr  8 19:24:43 insert dbtest.test 270ms
Thu Apr  8 19:24:45 insert dbtest.test 138ms
Thu Apr  8 19:24:51 insert dbtest.test 332ms
Thu Apr  8 19:24:51 insert dbtest.test 140ms
Thu Apr  8 19:24:52 insert dbtest.test 256ms
Thu Apr  8 19:24:52 insert dbtest.test 101ms
Thu Apr  8 19:24:52 insert dbtest.test 246ms
Thu Apr  8 19:24:52 insert dbtest.test 105ms
Thu Apr  8 19:24:52 insert dbtest.test 151ms
Thu Apr  8 19:24:53 insert dbtest.test 396ms
Thu Apr  8 19:24:53 OpCounters::gotOp unknown op: 38752749
op: 38752749
Thu Apr  8 19:24:53   Assertion failure 0 db/../util/message.h 119
0x4dcf16 0x4e5ab4 0x5de633 0x68d5b2 0x3bd4c0b20b 0x3301606617 0x3300ad3c2d
/usr/bin/mongod(_ZN5mongo12sayDbContextEPKc+0xe6) [0x4dcf16]
/usr/bin/mongod(_ZN5mongo8assertedEPKcS1_j+0x154) [0x4e5ab4]
/usr/bin/mongod(_ZN5mongo16assembleResponseERNS_7MessageERNS_10DbResponseERK11sockaddr_in+0x223) [0x5de633]
/usr/bin/mongod(_ZN5mongo10connThreadEv+0x232) [0x68d5b2]
/usr/lib64/libboost_thread-mt.so.4(thread_proxy+0x6b) [0x3bd4c0b20b]
/lib64/libpthread.so.0 [0x3301606617]
/lib64/libc.so.6(clone+0x6d) [0x3300ad3c2d]
Thu Apr  8 19:24:53   AssertionException in connThread, closing client connection
Thu Apr  8 19:24:53 connection accepted from 192.168.20.21:23516 #13
Thu Apr  8 19:24:58 allocating new datafile /var/lib/mongo/dbtest.32, filling with zeroes…
Thu Apr  8 19:25:24 done allocating datafile /var/lib/mongo/dbtest.32, size: 2047MB, took 25.824 secs
Thu Apr  8 19:25:24 insert dbtest.test 25888ms

mongodb的查询性能要差一些:

[root@web dist]# java -jar mongotest.jar mongo select 1000000 192.168.20.24 dbname5
Total run time:290 sec
Total rows:1000000
mongo select Result:3448row/sec

[root@web dist]# java -jar mongotest.jar mongo select 10000000 192.168.20.24 dbname5
Total run time:2952 sec
Total rows:10000000
mongo select Result:3387row/sec

后面准备把这个程序改成多线程的测一测mongodb的并发性能…

mongodb查询的语法

本文参考自官方的手册:

http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ConditionalOperators%3A%3C%2C%3C%3D%2C%3E%2C%3E%3D

1 ) . 大于,小于,大于或等于,小于或等于

$gt:大于
$lt:小于
$gte:大于或等于
$lte:小于或等于

例子:

db.collection.find({ "field" : { $gt: value } } ); // greater than : field > value
db.collection.find({ "field" : { $lt: value } } ); // less than : field < value
db.collection.find({ "field" : { $gte: value } } ); // greater than or equal to : field >= value
db.collection.find({ "field" : { $lte: value } } ); // less than or equal to : field <= value

如查询j大于3,小于4:

db.things.find({j : {$lt: 3}});
db.things.find({j : {$gte: 4}});

也可以合并在一条语句内:

db.collection.find({ "field" : { $gt: value1, $lt: value2 } } ); // value1 < field < value

2) 不等于 $ne

例子:

db.things.find( { x : { $ne : 3 } } );

3) in 和 not in ($in $nin)

语法:
db.collection.find( { "field" : { $in : array } } );

例子:

db.things.find({j:{$in: [2,4,6]}});
db.things.find({j:{$nin: [2,4,6]}});

4) 取模运算$mod

如下面的运算:
db.things.find( "this.a % 10 == 1")

可用$mod代替:

db.things.find( { a : { $mod : [ 10 , 1 ] } } )

5)  $all

$all和$in类似,但是他需要匹配条件内所有的值:

如有一个对象:

{ a: [ 1, 2, 3 ] }

下面这个条件是可以匹配的:

db.things.find( { a: { $all: [ 2, 3 ] } } );

但是下面这个条件就不行了:

db.things.find( { a: { $all: [ 2, 3, 4 ] } } );

6)  $size

$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:

下面的语句就可以匹配:db.things.find( { a : { $size: 1 } } );

官网上说不能用来匹配一个范围内的元素,如果想找$size<5之类的,他们建议创建一个字段来保存元素的数量。

You cannot use $size to find a range of sizes (for example: arrays with more than 1 element). If you need to query for a range, create an extra size field that you increment when you add elements.

7)$exists

$exists用来判断一个元素是否存在:

如:

db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回

8)  $type

$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。

db.things.find( { a : { $type : 2 } } ); // matches if a is a string
db.things.find( { a : { $type : 16 } } ); // matches if a is an int
9)正则表达式

mongo支持正则表达式,如:

db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写

10)  查询数据内的值

下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。db.things.find( { colors : "red" } );

11) $elemMatch

如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:

> t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 
{ "_id" : ObjectId("4b5783300334000000000aa9"),
"x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
}$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。

注意,上面的语句和下面是不一样的。

> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }

12)  查询嵌入对象的值

db.postings.find( { "author.name" : "joe" } );

注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation

举个例子:

> db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})

如果我们要查询 authors name 是Jane的, 我们可以这样:

> db.blog.findOne({"author.name" : "Jane"})

如果不用点,那就需要用下面这句才能匹配:

db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})

下面这句:

db.blog.findOne({"author" : {"name" : "Jane"}})

是不能匹配的,因为mongodb对于子对象,他是精确匹配。

13) 元操作符 $not 取反

如:

db.customers.find( { name : { $not : /acme.*corp/i } } );db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } ); mongodb还有很多函数可以用,如排序,统计等,请参考原文。

mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:

http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions

在centos 5.4上把mongodb 1.4.0编译成rpm包安装

rpm包还是比较好管理和升级的,今天试着把mongodb 1.4.0做成rpm包。

网上的文章比较少,只有自己摸索着做了。

首先需要先做一些准备工作:

安装epel库,这一步可有可无。
wget http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-3.noarch.rpm
rpm -ivh epel-release-5-3.noarch.rpm

安装一些相关的rpm,编译或运行mongo需要这些:
yum install -y bzip2-devel python-devel libicu-devel chrpath zlib-devel nspr-devel readline-devel ncurses-devel boost-devel pcre-devel js-devel readline-devel git tcsh scons gcc-c++ glibc-devel js js-devel

还需要将centos 5.4上的boost从1.33升级到1.38,mongodb建议1.34以上,更好的支持高并发情况。如果不升级,编译的时候会有相关的警告信息。

这一块想了很多办法,从官网http://www.boost.org/上下载源码包编译成rpm没有成功,而且版本差异过大,担心会有问题,所以偷了一下懒,直接用网上的src.rpm了。

下载:
wget ftp://195.220.108.108/linux/sourceforge/g/project/gr/gridiron2/support-files/FC10%20source%20RPMs/boost-1.38.0-1.fc10.src.rpm
或:
wget http://mirror.transact.net.au/sourceforge/g/project/gr/gridiron2/support-files/FC10%20source%20RPMs/boost-1.38.0-1.fc10.src.rpm

安装:
rpm -ivh boost-1.38.0-1.fc10.src.rpm

打包:
rpmbuild -ba /usr/src/redhat/SPECS/boost.spec

用刚刚编译的rpm包升级本机的boost:

rpm -Uvh /usr/src/redhat/RPMS/x86_64/boost-1.38.0-1.x86_64.rpm /usr/src/redhat/RPMS/x86_64/boost-devel-1.38.0-1.x86_64.rpm

查看一下:
[root@x64test ~]# rpm -qa | grep boost
boost-devel-1.38.0-1
boost-1.38.0-1

OK了,都是1.38版本的。

还要重新编译pcre,自带的编译时没带–enable-unicode-properties参数,用自带的编译出来的mongdb启动时会提示:
[root@x64test ~]# mongod
warning: some regex utf8 things will not work.  pcre build doesn’t have –enable-unicode-properties

我们下载src.rpm包重新编译:
[root@x64test ~]# wget http://mirrors.sohu.com/centos/5.4/os/SRPMS/pcre-6.6-2.el5_1.7.src.rpm
[root@x64test ~]# rpm -ivh pcre-6.6-2.el5_1.7.src.rpm
[root@x64test ~]# vi /usr/src/redhat/SPECS/pcre.spec
%configure –enable-utf8
改成:
%configure –enable-utf8 –enable-unicode-properties

[root@x64test ~]# rpmbuild -ba /usr/src/redhat/SPECS/pcre.spec

[root@x64test ~]# rpm -Uvh /usr/src/redhat/RPMS/x86_64/pcre-6.6-2.7.x86_64.rpm
[root@x64test ~]# rpm -Uvh /usr/src/redhat/RPMS/x86_64/pcre-devel-6.6-2.7.x86_64.rpm

下面开始编译mongodb 1.4.0:

1) 先下载:
wget http://downloads.mongodb.org/src/mongodb-src-r1.4.0.tar.gz

2) 解压:
tar -xvzf mongodb-src-r1.4.0.tar.gz

3) 按mongo.spec定义的文件名和目录重新做一个压缩包出来:
mv mongodb-src-r1.4.0  mongo-1.4.0
tar -czf mongo-1.4.0.tar.gz mongo-1.4.0

4) copy到打包目录:
cp mongo-1.4.0/rpm/mongo.spec /usr/src/redhat/SPECS/
cp mongo-1.4.0.tar.gz /usr/src/redhat/SOURCES/

5) mongo.spec有个小bug,还得改下:

vi /usr/src/redhat/SPECS/mongo.spec

找到第71行,将:
/usr/sbin/useradd -M -r -U -d /var/lib/mongo -s /bin/false
-c mongod mongod > /dev/null 2>&1
换成:
/usr/sbin/useradd -M -r -d /var/lib/mongo -s /bin/false
-c mongod mongod > /dev/null 2>&1

或者:
/usr/sbin/useradd -M -r -d /var/lib/mongo -s /bin/false
-c mongod mongod > /dev/null 2>&1 || true

这是一个bug,useradd没有-U这个参数,小写的-u倒是有。不改这个编译完成后,mongo-server会安装不成功。

上面一个更改经过测试没有问题,但是需要确保安装的时候系统内没有mongod用户存在,如果这个用户存在的话还是会报错(rpm -Uvh肯定就不行了)。后面的更改是为解决这个问题的,不过没有测试过。

6) 开始编译打包:
rpmbuild -ba /usr/src/redhat/SPECS/mongo.spec

7) 安装:
cp /usr/src/redhat/RPMS/x86_64/mongo*.rpm .
rpm -ivh mongo*.rpm

安装完成。

mysql 与 mongodb的性能对比

最近写了个java的程序来测试mysql 与mongodb的性能,代码如下:

package mongotest;
import com.mongodb.Mongo;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
import java.net.UnknownHostException;
import java.sql.*;

/**
*
* @author FarmerLuo
*/
public class Main {

    /**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
int rows = 0;
long start = System.currentTimeMillis();

//        try { Thread.sleep ( 3000 );
//        } catch (InterruptedException ie){}

        if ( args.length < 2 ) {
System.out.print("Lack parameter!!!n");
System.exit(1);
}

        if ( !args[0].equals("mysql") && !args[0].equals("mongo") ) {
System.out.print("First parameter: mysql or mongon");
System.exit(1);
}

        if ( !args[1].equals("insert") && !args[1].equals("update") ) {
System.out.print("Second parameter: insert or updaten");
System.exit(2);
}

        if ( args.length > 2 ) {
rows = Integer.parseInt(args[2]);
} else {
rows = 10000;
}

        if ( args[0].equals("mysql") ) {
if ( args[1].equals("insert") ) {
mysql_insert(rows);
} else {
mysql_update(rows);
}
} else {
if ( args[1].equals("insert") ) {
mongo_insert(rows);
} else {
mongo_update(rows);
}
}

        long stop = System.currentTimeMillis();
long endtime = (stop – start)/1000;
if ( endtime == 0 ) endtime = 1;
long result = rows/endtime;

System.out.print("Total run time:" + endtime + " secn");
System.out.print("Total rows:" + rows + "n");
System.out.print(args[0] + " " + args[1] + " Result:" + result + "row/secn");
}

    public static void mysql_insert(long len) {

        Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://192.168.20.24/test?user=root&password=1qaz2wsx&characterEncoding=UTF8");
// Do something with the Connection
} catch (SQLException ex) {
// handle any errors
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
Statement stmt = null;
try {
stmt = conn.createStatement();
} catch (SQLException ex) {
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
String str = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456";

//System.out.print(sql);
for( int j = 0; j < len; j++ ){
String sql = "insert into test (count, test1, test2, test3, test4) values (" + j + ",’" + str + "’,’" + str + "’,’" + str + "’,’" + str + "’)";
try {
stmt.executeUpdate(sql);
} catch (SQLException ex) {
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
}
}

public static void mysql_update(long len) {

        Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://192.168.20.24/test?user=root&password=1qaz2wsx&characterEncoding=UTF8");
// Do something with the Connection
} catch (SQLException ex) {
// handle any errors
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
Statement stmt = null;
try {
stmt = conn.createStatement();
} catch (SQLException ex) {
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
String str = "UPDATE7890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456";

//System.out.print(sql);
for( int j = 0; j < len; j++ ){
String sql = "update test set test1 = ‘" + str + "’,test2 = ‘" + str + "’ , test3 = ‘" + str + "’, test4 = ‘" + str + "’ where id = "+ j;
try {
stmt.executeUpdate(sql);
} catch (SQLException ex) {
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
}
}

    public static void mongo_insert(long len){
Mongo m = null;
try {
m = new Mongo("192.168.20.24", 27017);
} catch (UnknownHostException ex) {
System.out.println("UnknownHostException:" + ex.getMessage());
} catch (MongoException ex) {
System.out.println("Mongo Exception:" + ex.getMessage());
System.out.println("Mongo error code:" + ex.getCode());
}

        DB db = m.getDB( "dbname6" );

        DBCollection dbcoll = db.getCollection("test");
String str = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456";
for (int j = 0; j < len; j++) {
DBObject dblist = new BasicDBObject();
dblist.put("_id", j);
dblist.put("count", j);
dblist.put("test1", str);
dblist.put("test2", str);
dblist.put("test3", str);
dblist.put("test4", str);
try {
dbcoll.insert(dblist);
} catch (MongoException ex) {
System.out.println("Mongo Exception:" + ex.getMessage());
System.out.println("Mongo error code:" + ex.getCode());
}
}
}

    public static void mongo_update(long len){
Mongo m = null;
try {
m = new Mongo("192.168.20.24", 27017);
} catch (UnknownHostException ex) {
System.out.println("UnknownHostException:" + ex.getMessage());
} catch (MongoException ex) {
System.out.println("Mongo Exception:" + ex.getMessage());
System.out.println("Mongo error code:" + ex.getCode());
}

        DB db = m.getDB( "dbname6" );

        DBCollection dbcoll = db.getCollection("test");
String str = "UPDATE7890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456";
for (int j = 0; j < len; j++) {
DBObject dblist = new BasicDBObject();
DBObject qlist = new BasicDBObject();
qlist.put("_id", j);
dblist.put("test1", str);
dblist.put("test2", str);
dblist.put("test3", str);
dblist.put("test4", str);
try {
dbcoll.update(qlist,dblist);
} catch (MongoException ex) {
System.out.println("Mongo Exception:" + ex.getMessage());
System.out.println("Mongo error code:" + ex.getCode());
}
}
}
}

mysql为innodb,数据库表结构如下:

CREATE TABLE IF NOT EXISTS `test` (
`id` int(11) NOT NULL auto_increment,
`count` int(11) NOT NULL default ‘0’,
`test1` varchar(256) NOT NULL,
`test2` varchar(256) NOT NULL,
`test3` varchar(256) NOT NULL,
`test4` varchar(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

测试是在两台虚拟机之间进行,两台虚拟机在同一台exsi的物理机上,所以中间的网络延时基本为0。每行数据大小为1k。

测试结果:

1) mysql 插入50万行数据

[root@web dist]# java -jar "mongotest.jar" mysql insert 500000
Total run time:545 sec
Total rows:500000
mysql insert Result:917row/sec

资源占用:

Cpu(s): 7.4%us, 4.7%sy, 0.0%ni, 11.7%id, 72.6%wa, 0.7%hi, 3.0%si, 0.0%st   load average为1以下

2)mysql更新50万行数据

[root@web dist]# java -jar "mongotest.jar" mysql update 500000
Total run time:838 sec
Total rows:500000
mysql update Result:596row/sec

资源占用:

Cpu(s): 7.4%us, 3.3%sy, 0.0%ni, 6.7%id, 80.6%wa, 0.7%hi, 1.3%si, 0.0%st     load average为1以下

3) mongo插入50万行数据

[root@web dist]# java -jar "mongotest.jar" mongo insert 500000    
Total run time:52 sec
Total rows:500000
mongo insert Result:9615row/sec

把数据清空,第二次跑测试程序,速度要慢一些。

[root@web dist]# java -jar "mongotest.jar" mongo insert 500000
Total run time:60 sec
Total rows:500000
mongo insert Result:8333row/sec

资源占用:

Cpu(s): 6.0%us, 3.0%sy, 0.0%ni, 0.0%id, 88.6%wa, 0.3%hi, 2.0%si, 0.0%st load average为1.5~2.0

4) mongo更新50万行数据

[root@web dist]# java -jar "mongotest.jar" mongo update 500000
Total run time:32 sec
Total rows:500000
mongo update Result:15625row/sec

资源占用:

Cpu(s): 90.0%us, 7.4%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 2.7%si, 0.0%st     load average为1以下

5) mysql 插入100万行数据

[root@web dist]# java -jar "mongotest.jar" mysql insert 1000000
Total run time:1085 sec
Total rows:1000000
mysql insert Result:921row/sec

资源占用和50万差不多。

6) mysql 更新100万行数据

[root@web dist]# java -jar "mongotest.jar" mysql update 1000000
Total run time:1646 sec
Total rows:1000000
mysql update Result:607row/sec

资源占用和50万差不多。

7) mongo插入100万行数据

[root@web dist]# java -jar "mongotest.jar" mongo insert 1000000   
Total run time:120 sec
Total rows:1000000
mongo insert Result:8333row/sec

资源占用明显增高了很多,系统基本不能操作了。

top – 14:52:10 up 2 days, 5:00, 1 user, load average: 3.84, 1.41, 0.98
Tasks: 78 total,   2 running, 76 sleeping,   0 stopped,   0 zombie
Cpu(s): 6.4%us, 26.2%sy, 0.0%ni, 0.0%id, 63.6%wa, 0.0%hi, 3.7%si, 0.0%st
Mem:   2059620k total, 2049616k used,    10004k free,     1692k buffers
Swap: 1048568k total,   988112k used,    60456k free, 1380512k cached

PID USER      PR NI VIRT RES SHR S %CPU %MEM    TIME+ COMMAND                                                                
2817 root      16   0 2328m 614m 612m S 12.5 30.5   8:01.53 mongod   

8) mongo更新100万行数据

[root@web dist]# java -jar "mongotest.jar" mongo update 1000000
Total run time:66 sec
Total rows:1000000
mongo update Result:15151row/sec

资源占用:

top – 14:58:14 up 2 days, 5:06, 1 user, load average: 0.53, 0.99, 0.97
Tasks: 75 total,   2 running, 73 sleeping,   0 stopped,   0 zombie
Cpu(s): 89.7%us, 6.7%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.3%hi, 3.3%si, 0.0%st
Mem:   2059620k total, 2048632k used,    10988k free,     2468k buffers
Swap: 1048568k total, 1046996k used,     1572k free, 1578768k cached

PID USER      PR NI VIRT RES SHR S %CPU %MEM    TIME+ COMMAND                                                                
2817 root      16   0 3352m 1.2g 1.2g S 98.6 62.1   9:46.79 mongod   

9) mongo插入1000万行数据

[root@web dist]# java -jar "mongotest.jar" mongo insert 10000000
Total run time:774 sec
Total rows:10000000
mongo insert Result:12919row/sec

资源占用:

top – 15:14:17 up 2 days, 5:23, 1 user, load average: 4.56, 4.04, 2.64
Tasks: 75 total,   2 running, 73 sleeping,   0 stopped,   0 zombie
Cpu(s): 28.5%us, 9.3%sy, 0.0%ni, 0.0%id, 57.0%wa, 1.0%hi, 4.3%si, 0.0%st
Mem:   2059620k total, 2049132k used,    10488k free,     1580k buffers
Swap: 1048568k total, 1047520k used,     1048k free, 1556816k cached

PID USER      PR NI VIRT RES SHR S %CPU %MEM    TIME+ COMMAND                                                                
2817 root      16   0 13.3g 1.5g 1.5g S 35.3 75.3 14:31.29 mongod

10) mongo更新1000万行数据

[root@web dist]# java -jar "mongotest.jar" mongo update 10000000
Total run time:830 sec
Total rows:10000000
mongo update Result:12048row/sec

资源占用:

top – 15:22:45 up 2 days, 5:31, 1 user, load average: 1.31, 1.69, 1.99
Tasks: 75 total,   2 running, 73 sleeping,   0 stopped,   0 zombie
Cpu(s): 48.7%us, 5.0%sy, 0.0%ni, 0.0%id, 42.3%wa, 0.7%hi, 3.4%si, 0.0%st
Mem:   2059620k total, 2049772k used,     9848k free,     1336k buffers
Swap: 1048568k total, 1044068k used,     4500k free, 1559972k cached

PID USER      PR NI VIRT RES SHR S %CPU %MEM    TIME+ COMMAND                                                                
2817 root      16   0 13.3g 1.5g 1.5g S 54.3 75.6 16:52.04 mongod