PHPのPDOやMySQLiでlocalhostの名前解決が出来ない原因

“localhost”という名前を使ったときに、エラーになることがありました。

$pdo = new PDO('mysql:host=localhost;port=8889;dbname=mysql', "root", "root");

↑これで、localhostの名前解決をしてくれません。どうやらUnixDomainSocketに繋がるようです。”localhost”の代わりに、”127.0.0.1″だと問題なく出来ました。

原因としては、↓のようです。

When “localhost” is specified, MySQL uses a socket connections (e.g. /var/run/mysqld/mysqld.sock). “127.0.0.1” forces it to connect using a TCP connection. Your problem may occur because your MySQL client and MySQL server are configured to use different socket paths. This may happen e.g. if PHP and MySQL are installed from different sources, or if either of them somehow picks up its configuration from the wrong config file.

https://drupal.org/node/683564


環境構築の過程でうまくいかなかった場合、”localhost”を指定してもUnixDomainSocketが優先されることもあるようですね。。。名前解決を期待せずに”127.0.0.1″を素直に使うと良いかもしれません。

PHP の MySQLi を使って、MySQL のバージョンとサイズを求める

表題のように、MySQL のバージョンとサイズを求めてみました。
mysqli は PDO と違って少々分かりにくかったです。。。
ホストやポート、データベース名は適宜書き換えてください。

コード

<?php

$mysqli = new mysqli("localhost:8889", "root", "root", "mysql");
$query = $mysqli->prepare("select version()");
$query->execute();
$query->bind_result($version);
$query->fetch();
echo 'MySQL version: ' . $version . "\n";
$query->close();

$query = $mysqli->prepare("SELECT concat(round(sum(data_length+index_length)/(1024*1024),2)) total_size FROM information_schema.TABLES");
$query->execute();
$query->bind_result($current_usage);
$query->fetch();
$query->close();
echo 'MySQL Current Usage (MB): ' . $current_usage . "\n";


実行結果
MySQL version: 5.5.29
MySQL Current Usage (MB): 0.44

MySQLでのユーザーとパスワードとデータベースの作成

覚書です。

まずルートで入る

usernameとpasswordを設定する(username: hoge, password: secretpasswordとします)

flushする

です。

# mysqlをport 8889で立ち上げているとします(MySQLのデフォルトのポートは3306です)。
$ mysql5 -h 127.0.0.1 -P 8889 -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 35
Server version: 5.5.29 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

root@localhost [(none)] > show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

root@localhost [(none)] > GRANT ALL PRIVILEGES ON *.* TO hoge
    -> IDENTIFIED BY 'secretpassword' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

root@localhost [(none)] > FLUSH PRIVILEGES;

root@localhost [(none)] > CREATE DATABASE t01 CHARACTER SET utf8;
Query OK, 1 row affected (0.00 sec)

root@localhost [(none)] > use hoge
Database changed
root@localhost [hoge] > 

↑ただし、これだとlocalhostから繋ぐことが出来ません。。。外部からなら繋ぐことは出来ますが。。。localhostで繋ぎたい場合は、
mysql> GRANT ALL PRIVILEGES ON *.* TO hoge@'localhost' IDENTIFIED BY 'secretpassword' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

こんな感じです。MySQLのコンフィグで、bind-address = 127.0.0.1だとローカルからでしか繋がりませんので、bind-address = 0.0.0.0とするか、コメントアウトしましょう。

ユーザーを削除するには、

drop user hoge@'localhost';

ですね。

MySQLのベンチマーク

追記@2014-07-16
mysqlslapの他にもベンチマークソフトは様々あります。mybench: http://jeremy.zawodny.com/mysql/mybench/ もいいと思います。具体的には、自分が作ったスキーマに対してベンチをしたりでき柔軟です。mysqlslapと合わせて使うと良いかもです。
使い方は検索して下さい。


=== まとめここから ===

mysqlslapの結果まとめ

OS MySQL Version MySQL Engine CPU Storage Read (req/sec) Write (req/sec)
Debian 7.2 5.5.31 InnoDB Pentium DualCore E5200 Crucial m4 CT064M4SSD2 (64GB SSD) 27800.9 18892.8
Ubuntu 12.04.3 LTS 5.5.34 InnoDB Opteron 3280 Hitachi HDT721010SLA360 14806.0 9145.7
Ubuntu 12.04.3 LTS 5.5.34 InnoDB Celeron G540 ST500NM0011 39370.0 14359.5

やはりSSDは高速ですね。DBでは信頼性を確保するためにはどうしても不揮発性の媒体に書いておく必要があり、そのストレージで性能が決まるようです。不揮発性メモリが楽しみですね!

今回↑で使ったinsertのクエリの具体例は↓です。
INSERT INTO t1 VALUES 
(uuid(),1976594918,'xHogEXydBNC1CRXW0HkRAR8A2T2R04JxDzTKWRxai2buLyHMF1hQKicN3Wq3Q2sg1L0OhxyNrZADYRRnS0Doii3mCuhfoaJpnBDS0Bksdu59LYohYuL7cPlgBQJz0W')

ところで、Celeron G540 + ST500NM0011の組み合わせが健闘しています。読み込みはE5200 + SSDより高速ですし(メモリに全部載っていて、DRAMの速度の違いなのかもです、E5200の方はDDR2-800なので)、書き込みもHDDを使っているにも関わらずSSDの半分の速度が出ています。HDD自体の速度向上と、キャッシュによるものなのでしょうかね。

ふと思ったのですが、HDDやSSDにはDRAMのキャッシュが載っています(WD Blackですと64MBほど)。それに書き込んだ時点でOKを返すのでしょうか?だとしたらあまり信頼性が高くないような、、、という気がしてきました。その辺の議論ってどうなっているのでしょうね?確か某SSDですと、電源断が起こったときはコンデンサに貯めこんでおいた電気を使うはずです(なのでコンデンサが充電されていない状態で落ちるとデータは揮発します)。HDDだとどうなんでしょうね。まあトラブルは電源断だけではないので(OOM Killerに落とされるとか)、難しいところですが。。。

また、↑のベンチマークでは、Celeron G540でReadが3.9万req/sec、Writeが1.4万req/sec程度出ていて、早すぎないかと疑問に思いました。しかし、Amazon Relational Database Serviceによると、

データベースインスタンスごとに最大 3 TB のストレージ、30,000 IOPS をプロビジョニングできます。m2.4xlarge インスタンスで実行される 50% の書き込み、50% の読み取り作業負荷に対し、Oracle は最大 25,000 IOPS まで実現できます。cr1.8xlarge で実行している同様の作業負荷では、MySQL または PostgreSQL は最大 20,000 IOPS まで実現


とありますので、ほぼ一致と言えるでしょう。というのも、
>50% の書き込み、50% の読み取り作業負荷
を今回の私のベンチで言うと、3.9 * 0.5 + 1.4 * 0.5 = 2.65 万 [req/sec]となり、この計算結果は「最大 20,000 IOPS」と近い値だからです。

=== まとめここまで ===

MySQLのベンチマークをどのように取るかは悩ましいところだと思います。

– mysqlslapを使う
– アプリケーション側で記述してみる

などのやり方があると思います。アプリケーション側だとコンカレンシーを増やすなどがやりにくいので、基本的にはベンチマークツールを使いたいところですね。mysqlslapはデフォルトで付属しているツールなのですが、オプションが多すぎていまいち使い勝手がよくないです。。。

が、調べてみると丁寧に解説がなされたものをいくつか見つけました。

MySQL5.5と、mysqlslapについて

↑かなり参考にさせていただきました。

という訳でベンチマークを取ってみました。MySQLのコンフィグファイルの設定は山ほどあります。今回は速度と信頼性の中間ぐらいの、標準的なものにしてみました。

マシンA(ベンチマーク対象)
– DMI: System manufacturer System Product Name/P5KPL-CM, BIOS 0514 08/14/2008
– Intel Corporation 82G33/G31/P35/P31 Express DRAM Controller (rev 10)
– Intel Pentium(R) Dual-Core CPU E5200 @ 2.50GHz stepping 06
– M4-CT064M4SSD2
– Ethernet controller: Atheros Communications Inc. AR8121/AR8113/AR8114 Gigabit or Fast Ethernet (rev b0)
– Linux version 3.2.0-4-amd64 (debian-kernel@lists.debian.org) (gcc version 4.6.3 (Debian 4.6.3-14) ) #1 SMP Debian 3.2.51-1

マシンAの準備

# mysqlをインストール
$ sudo aptitude install mysql-server

# version確認
$ mysql --version
mysql  Ver 14.14 Distrib 5.5.31, for debian-linux-gnu (x86_64) using readline 6.2

# テスト用ユーザーの作成 (username: piyo, password: piyo)
$ mysql -u root -p

mysql> GRANT ALL PRIVILEGES ON *.* TO piyo
    -> IDENTIFIED BY 'piyo' WITH GRANT OPTION;

# my.confの編集 (後述)
$ sudo vi /etc/mysql/my.cnf

# restart
$ sudo service mysql restart

注意点として↑で作ったユーザーは、ローカルホストからはアクセスできません。なので他のマシンからアクセスしてください。localhostからアクセス出来るようにするには、↓を打ち込みます。
mysql> GRANT ALL PRIVILEGES ON *.* TO piyo@'localhost' IDENTIFIED BY 'piyo' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

さて、マシンBを用意します(mysqlをインストールしておいてください)。マシンAとはGbEスイッチングハブなどでつなぎます。

マシンBからベンチマーク(mysqlslap)を実行 (同時実行数は10,実行回数は1万回で合計10万リクエスト)
# 読み込み
$ mysqlslap --no-defaults --create-schema=SLAP --auto-generate-sql --auto-generate-sql-guid-primary --engine=InnoDB --number-int-cols=1 --number-char-cols=1 --concurrency=10 --auto-generate-sql-write-number=10000 --auto-generate-sql-execute-number=10000 --auto-generate-sql-load-type=key --iterations=3 --user=piyo --password=piyo --host=192.168.1.118 --port=3306
Benchmark
	Running for engine InnoDB
	Average number of seconds to run all queries: 3.563 seconds
	Minimum number of seconds to run all queries: 3.440 seconds
	Maximum number of seconds to run all queries: 3.649 seconds
	Number of clients running queries: 10
	Average number of queries per client: 10000

# 書き込み
$ mysqlslap --no-defaults --create-schema=SLAP --auto-generate-sql --auto-generate-sql-guid-primary --engine=InnoDB --number-int-cols=1 --number-char-cols=1 --concurrency=10 --auto-generate-sql-write-number=10000 --auto-generate-sql-execute-number=10000 --auto-generate-sql-load-type=write --iterations=3 --user=piyo --password=piyo --host=192.168.1.118 --port=3306
Benchmark
	Running for engine InnoDB
	Average number of seconds to run all queries: 5.071 seconds
	Minimum number of seconds to run all queries: 4.766 seconds
	Maximum number of seconds to run all queries: 5.344 seconds
	Number of clients running queries: 10
	Average number of queries per client: 10000

ちなみに↑を実行中のマシンAの状態です。
# 読み込み時
$ dstat
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw 
  9   3  87   2   0   0|  18k 2652k|   0     0 |   0     0 |1786  8163 
  0   0 100   0   0   0|   0     0 | 984B 1664B|   0     0 |  40    86 
 16   6  77   1   0   0|   0    88k| 596k  191k|   0     0 |5192  6927 
 20   9  71   1   0   0|   0  1764k| 809k  258k|   0     0 |6573  8770 
 40  12  46   1   0   2|   0  1844k|1694k 2289k|   0     0 |  17k   30k
 54  27  12   1   0   7|   0   588k|2988k 6586k|   0     0 |  31k   58k
 41  36  18   0   0   6|   0   168k|5698k   12M|   0     0 |  32k   60k
 38  37  21   0   0   5|   0   120k|3991k 8797k|   0     0 |  31k   58k
 20   5  73   2   0   1|   0   316k|1878k 2761k|   0     0 |6553  8910 
 19   4  77   1   0   0|   0  1852k| 630k  201k|   0     0 |5415  7226 
 27  10  60   2   0   2|   0  2148k| 790k  252k|   0     0 |  11k   18k
 54  28  12   0   0   6|   0  1196k|3888k 8531k|   0     0 |  32k   62k
 39  41  12   1   0   8|   0  1072k|3511k 7740k|   0     0 |  29k   53k
 38  43  13   0   0   6|   0   360k|5575k   12M|   0     0 |  30k   55k
 22  17  58   1   0   2|   0   452k|2005k 4030k|   0     0 |  13k   21k
 19   6  71   4   0   0|   0  7496k|1126k  360k|   0     0 |5898  7940 
 18   7  71   4   0   0|   0  5724k| 706k  226k|   0     0 |6081  8174 
 54  25  15   0   0   6|   0  1196k|3411k 7270k|   0     0 |  30k   58k
 45  34  15   1   0   5|   0   360k|3673k 8096k|   0     0 |  32k   58k
 36  42  18   0   0   4|   0   328k|3910k 8618k|   0     0 |  33k   61k
 20  15  64   0   0   1|   0   384k|3892k 8576k|   0     0 |  15k   28k
  0   0  99   1   0   0|   0   384k|  66B  354B|   0     0 |  67   127 
  0   1  99   1   0   0|   0   992k| 132B  468B|   0     0 | 103   208 
  1   0  95   4   0   0|   0  5192k| 132B  468B|   0     0 | 157   329 

# 書き込み時
$ dstat
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw 
  9   3  86   2   0   0|  18k 2643k|   0     0 |   0     0 |1806  8176 
  0   0 100   0   0   0|   0     0 | 444B 1322B|   0     0 |  38    87 
 17  10  72   1   0   1|   0    84k| 773k  247k|   0     0 |6330  8465 
 19   9  71   1   0   0|   0  1528k| 803k  256k|   0     0 |6519  8707 
 40  16  38   2   0   4|   0  5924k|3490k 1493k|   0     0 |  11k   19k
 54  19  15   8   0   5|   0    20M|3751k 1201k|   0     0 |  13k   25k
 52  16  18  10   0   5|   0    21M|5419k 1735k|   0     0 |  12k   23k
 55  22  14   5   0   5|   0    18M|4257k 1362k|   0     0 |  14k   27k
 52  18  19   7   0   5|   0    17M|3452k 1106k|   0     0 |  13k   24k
 33   9  50   6   0   2|   0    14M|4277k 1369k|   0     0 |8310    14k
 19   9  71   2   0   0|   0  2232k| 784k  251k|   0     0 |6441  8622 
 23   9  65   2   0   1|   0  3668k|1194k  381k|   0     0 |6888  9461 
 46  13  22  15   0   4|   0    13M|3164k 1391k|   0     0 |  11k   20k
 52  19  18   7   0   4|   0    18M|5428k 1739k|   0     0 |  13k   24k
 50  17  20   9   0   4|   0    22M|3943k 1262k|   0     0 |  12k   23k
 55  19  15   6   0   5|   0    11M|3515k 1126k|   0     0 |  14k   26k
 47  14  23  12   0   4|   0    23M|4953k 1588k|   0     0 |  11k   21k
 34  14  47   4   0   2|   0  7588k|2844k  910k|   0     0 |9035    15k
 20   8  68   4   0   1|   0  6384k|1075k  344k|   0     0 |6312  8416 
 20   9  69   3   0   0|   0  5024k| 817k  261k|   0     0 |6422  8589 
 49  20  20   7   0   3|   0    17M|4472k 1811k|   0     0 |  13k   23k
 53  21  16   6   0   6|   0    18M|4299k 1376k|   0     0 |  14k   25k
 55  18  16   7   0   5|   0    18M|3877k 1241k|   0     0 |  14k   25k
 52  16  20   8   0   5|   0    19M|5826k 1865k|   0     0 |  13k   23k
 53  20  15   7   0   5|   0    14M|3736k 1196k|   0     0 |  13k   25k
  3   1  94   3   0   0|   0  5668k|1576k  504k|   0     0 | 459   800 
  1   0  98   1   0   0|   0  2684k|  66B  354B|   0     0 | 109   198 
  0   0  99   1   0   0|   0  1432k|  66B  354B|   0     0 |  63   117 
  1   0  99   1   0   0|   0   824k|  66B  354B|   0     0 | 110   197

↑読み込み時にもけっこうなdisk writeがありますが、WAL(Write Ahead Log)なのでしょうか。selectでは意味がなさそうですが。。。それと、↑を見ると、MySQLプロトコルが古いのかなという気がします、というのもRedisあたりのベンチマーク中にdstatを見ますと、読み込みと書き込み時では、net/totalの桁が異なるからです。具体的には読み込み時はrecvがわずかで、sendが大きくなります。

ちなみに、いろんなマシンで計測した結果を一番上の表にまとめておきます。

my.cnfの内容を以下に置いておきます。速度と信頼性の中間を取った感じです。デフォルトから書き換えた・追加した項目は以下の4項目です。

– bind-address = 0.0.0.0
– innodb_buffer_pool_size = 1G
– innodb_flush_log_at_trx_commit = 2
– sync_binlog = 1
– innodb_flush_method = O_DIRECT

bind-addressについてですが、127.0.0.1だとローカルホストからのみアクセス可能です。ですので0.0.0.0としてグローバルで取れるようにしておきます。その他の↑のオプションについては検索してみてください。

my.conf
#
# The MySQL database server configuration file.
#
# You can copy this to one of:
# - "/etc/mysql/my.cnf" to set global options,
# - "~/.my.cnf" to set user-specific options.
# 
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html

# This will be passed to all mysql clients
# It has been reported that passwords should be enclosed with ticks/quotes
# escpecially if they contain "#" chars...
# Remember to edit /etc/mysql/debian.cnf when changing the socket location.
[client]
port		= 3306
socket		= /var/run/mysqld/mysqld.sock

# Here is entries for some specific programs
# The following values assume you have at least 32M ram

# This was formally known as [safe_mysqld]. Both versions are currently parsed.
[mysqld_safe]
socket		= /var/run/mysqld/mysqld.sock
nice		= 0

[mysqld]
#
# * Basic Settings
#
user		= mysql
pid-file	= /var/run/mysqld/mysqld.pid
socket		= /var/run/mysqld/mysqld.sock
port		= 3306
basedir		= /usr
datadir		= /var/lib/mysql
tmpdir		= /tmp
lc-messages-dir	= /usr/share/mysql
skip-external-locking
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
#bind-address		= 127.0.0.1
bind-address = 0.0.0.0

#
# * Fine Tuning
#
key_buffer		= 16M
max_allowed_packet	= 16M
thread_stack		= 192K
thread_cache_size       = 8
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
myisam-recover         = BACKUP
#max_connections        = 100
#table_cache            = 64
#thread_concurrency     = 10
#
# * Query Cache Configuration
#
query_cache_limit	= 1M
query_cache_size        = 16M
#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
# As of 5.1 you can enable the log at runtime!
#general_log_file        = /var/log/mysql/mysql.log
#general_log             = 1
#
# Error logging goes to syslog due to /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
#
# Here you can see queries with especially long duration
#log_slow_queries	= /var/log/mysql/mysql-slow.log
#long_query_time = 2
#log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
#       other settings you may need to change.
#server-id		= 1
#log_bin			= /var/log/mysql/mysql-bin.log
expire_logs_days	= 10
max_binlog_size         = 100M
#binlog_do_db		= include_database_name
#binlog_ignore_db	= include_database_name
#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
#
# * Security Features
#
# Read the manual, too, if you want chroot!
# chroot = /var/lib/mysql/
#
# For generating SSL certificates I recommend the OpenSSL GUI "tinyca".
#
# ssl-ca=/etc/mysql/cacert.pem
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem

innodb_buffer_pool_size = 1G
innodb_flush_log_at_trx_commit = 2
sync_binlog = 1
innodb_flush_method = O_DIRECT

[mysqldump]
quick
quote-names
max_allowed_packet	= 16M

[mysql]
#no-auto-rehash	# faster start of mysql but no tab completition

[isamchk]
key_buffer		= 16M

#
# * IMPORTANT: Additional settings that can override those from this file!
#   The files must end with '.cnf', otherwise they'll be ignored.
#
!includedir /etc/mysql/conf.d/

MongoDBのjournalCommitIntervalとパフォーマンスの関係

MongoDBにはjournaling機能があります。ファイルシステムなど不勉強であまり理解していませんが、RDBでよくあるWAL、Write Ahead Logと同じ機能だと思います。測定結果から書きますと (#1は1回目、#2は2回目、という意味です)、

journalCommitInterval [ms] #1 [req/sec] #2 [req/sec] #3 [req/sec]
2 2750.77 2742.48 2745.22
5 3753.11 4643.63 3668.53
10 5878.66 5964.59 5811.40
20 6940.56 6907.89 6978.47
50 6994.27 7187.60 7055.46
100 7750.13 7833.18 7759.90
200 7984.70 7939.39 8021.59
300 8034.18 7852.37 7965.44
no journal 8238.88 8317.84 8289.27

となりました。書き込みの内容・サイズは、
$doc = array(
        'key1' => 'value1',
        'key2' => 'value2',
        'time' => time(),
);

です。time()は、unixtimeが整数値で出てきます。なんとなくtime()だとボトルネックになりそうですが、time()の代わりに適当な文字列にしてみてもパフォーマンスに変化はみられませんでした。

書き込み間隔が長いほどパフォーマンスが良いという順当な結果です。間隔が100~300[ms]程度だと、no journalの場合とあまり変わりません。なのでパフォーマンス重視の実運用を考えると100ぐらいに設定しておくのが良さそうです。

スペックは、
– NEC Express5800/S70 [N8100-9023]/MSS0332
– Linux version 3.2.0-52-generic (buildd@roseapple) (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #78-Ubuntu SMP Fri Jul 26 16:21:44 UTC 2013 (Ubuntu 3.2.0-52.78-generic 3.2.48)
– DRAM: 8GB * 2
– SEAGATE ST500NM0011 (500GB HDD)
– Intel(R) Celeron(R) CPU G540 @ 2.50GHz stepping 07
– mongodb-linux-x86_64-2.4.8
– PHP 5.3.10-1ubuntu3.7 with Suhosin-Patch (cli) (built: Jul 15 2013 18:05:44)
– PHP mongo 1.4.0 stable
です。いまどきHDDなので残念感ありますが。。。SSDのベンチマークはどなたかお願いします。

MongoDB公式の設定オプションには、
>Lower values increase the durability of the journal, at the possible expense of disk performance
と書いてある通りの結果となりました。2 [ms]に指定した場合、パフォーマンスは約2700 [req/sec]程度になってしまいます。MySQLのベンチマークをしたときにこれぐらいだった記憶があり、早いとされているMongoDBでも、書き込みの信頼性を高めると結局MySQLなどとパフォーマンスに大差がないことが分かります。というよりこのあたりが現在のアーキテクチャ、ハードでの限界点なのでしょう。

永続化しつつ、パフォーマンス向上を成し遂げるにはスケールアウトする他なさそうです。

このようにjournalingやWALを考えますと、不揮発性メモリの到来が待ち遠しいですね(もう出来ているようですが、ある程度安価という意味で^^)。多くのDBが10倍以上の高速化を果たす可能性が高いでしょう。

実行コマンド
# CommitIntervalは↓のようにして設定します。2~300まで選択可能のようです
$ ./bin/mongod --journalCommitInterval 300

# journalなしの場合は、↓です。
$ ./bin/mongod  --nojournal

ベンチマークスクリプト
<?php

$mongo = new MongoClient('mongodb://' . 'localhost' . ":" . '27017');

$max = 10000;
$ids = array();
$bench = new Benchmark();
for ($i = 0; $i < $max; $i++) {
	$ids[] = insertSomething($mongo);
}
printf("%.2f [req/sec]\n", $max / $bench->end());

function insertSomething(MongoClient $mongo) {
	$db = $mongo->user;
	$col = $db->user;
	$doc = array(
		'key1' => 'value1',
		'key2' => 'value2',
		'time' => time(),
	);
	$col->insert($doc);

	return $doc['_id'];
}

class Benchmark {

	private $start;

	public function __construct() {
		$this->start();
	}

	private function start() {
		$this->start = microtime(TRUE);
	}

	public function end() {
		return (double) (microtime(TRUE) - $this->start);
	}

}


ちなみに、「–journalCommitInterval 1」とすると、エラー↓になるのですが、
# ./bin/mongod --journalCommitInterval 1
Wed Nov 13 12:29:10.772 --journalCommitInterval out of allowed range (0-300ms)
Wed Nov 13 12:29:10.773 dbexit: 
Wed Nov 13 12:29:10.773 shutdown: going to close listening sockets...
Wed Nov 13 12:29:10.773 shutdown: going to flush diaglog...
Wed Nov 13 12:29:10.773 shutdown: going to close sockets...
Wed Nov 13 12:29:10.773 shutdown: waiting for fs preallocator...
Wed Nov 13 12:29:10.773 shutdown: lock for final commit...
Wed Nov 13 12:29:10.773   Assertion failure c src/mongo/db/client.h 235
0xde05e1 0xda15bd 0x8c9768 0x8c9e6c 0x8ca262 0x8cc83d 0x8ccb75 0x9f2880 0x9f2fa2 0x6d8da9 0x6df459 0x7fa2028c976d 0x6cf1c9 
 ./bin/mongod(_ZN5mongo15printStackTraceERSo+0x21) [0xde05e1]
 ./bin/mongod(_ZN5mongo12verifyFailedEPKcS1_j+0xfd) [0xda15bd]
 ./bin/mongod(_ZN5mongo4Lock26ParallelBatchWriterSupport6relockEv+0x248) [0x8c9768]
 ./bin/mongod(_ZN5mongo4Lock26ParallelBatchWriterSupportC1Ev+0x2c) [0x8c9e6c]
 ./bin/mongod(_ZN5mongo4Lock10ScopedLockC2Ec+0x32) [0x8ca262]
 ./bin/mongod(_ZN5mongo4Lock10GlobalReadC1Ei+0x1d) [0x8cc83d]
 ./bin/mongod(_ZN5mongo11readlocktryC1Ei+0x45) [0x8ccb75]
 ./bin/mongod() [0x9f2880]
 ./bin/mongod(_ZN5mongo6dbexitENS_8ExitCodeEPKc+0x172) [0x9f2fa2]
 ./bin/mongod() [0x6d8da9]
 ./bin/mongod(main+0x9) [0x6df459]
 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7fa2028c976d]
 ./bin/mongod(__gxx_personality_v0+0x499) [0x6cf1c9]
Wed Nov 13 12:29:10.776 shutdown failed with exception
Wed Nov 13 12:29:10.776 dbexit: really exiting now
↑の中に、「Wed Nov 13 12:29:10.772 –journalCommitInterval out of allowed range (0-300ms)」と書いてあります。「1」は範囲内に見えるのですがどういうことなのでしょう。。。「0」でも同じエラーが出ます。公式には、
>This option accepts values between 2 and 300 milliseconds.
と書いてありますので、mongodのドキュメントの間違いでしょう。

ちなみに、以下のコードの用に、MongoClientの代わりにMongoCollectionを引数にしてみたところ、パフォーマンスが若干向上しました。具体的には、journalCommitIntervalが300のときに、8577.61 [req/sec]程度になりました。+10%程度は上がっているようです。実装を知らないので確証はないのですが、$db = $mongo->user; $col = $db->user;の段階で通信が行われているのかもしれません。tcpdumpして見てみるべきでしょう。。。

ちょっぴり早いコード
<?php

$mongo = new MongoClient('mongodb://' . 'localhost' . ":" . '27017');
$db = $mongo->user;
$col = $db->user;

$max = 10000;
$ids = array();
$bench = new Benchmark();
for ($i = 0; $i < $max; $i++) {
	$ids[] = insertSomething($col);
}
printf("%.2f [req/sec]\n", $max / $bench->end());

function insertSomething(MongoCollection $col) {
	$doc = array(
		'key1' => 'value1',
		'key2' => 'value2',
		'time' => time(),
	);
	$col->insert($doc);

	return $doc['_id'];
}

class Benchmark {

	private $start;

	public function __construct() {
		$this->start();
	}

	private function start() {
		$this->start = microtime(TRUE);
	}

	public function end() {
		return (double) (microtime(TRUE) - $this->start);
	}

}


さらに蛇足です。
Opteron 3280、その他条件はNECサーバーと同じのマシンで同じベンチマークをしてみました。
# ./bin/mongod --journalCommitInterval 300
という状態で、行ってみますと、3290.90 [req/sec]、でした。だいぶ遅いですね、半分以下の性能になってしまっています。

Celeron G540とOpteron3280の1コアあたりの性能は、Celeronが若干上で、全体の性能はコア数で稼ぐOpteronが高い、という結論が普段のベンチマークからは導かれているのですが。。。

バイナリ版のMongoDBを使っている影響かもしれません。。。つまりIntelに最適化されたバイナリの可能性が高いと思います。ソースからコンパイルするのは面倒なのでしませんが、まあこういうことがありましたということで。。。こんな下の方のページ、誰も見ていないでしょうけれど。

-> Opteronの方でMongoDBをソースからコンパイルしてパフォーマンスを取ってみましたが、バイナリ版と差がありません。。。Celeron G540の方もソースからやってみましたが、バイナリと変わらない成績でした。うーむ、バイナリ版MongoDBで十分のようです。