Hatena::ブログ(Diary)

@camelmasaの開発日記 このページをアンテナに追加 RSSフィード

Githubで活動しています。

2011-07-31

「第5回 MongoDB 勉強会 in Tokyo」〜真夏の大Mongo祭り〜 で発表しました!

| 17:20

GridFSについて調査して挙動を確認した事を報告しました。

久しぶりにお会い出来た方々、とても嬉しかったです。有難うございます!


ATND

http://atnd.org/events/17136



slideshare

フォント変わってしまうので見にくいな。



[PR]Spreeの情報を集めています。

ECを持ちたい方、仕事でECを使いたい方向けのコミュニティサイトです。

このサイトでは世界で最も使用されているECの1つであるSpreeについての情報を提供しています。

http://spreecommerce.jp/

2010-04-22

最先端PHPフレームワークLithiumのチュートリアルを実際に体験してみました。

| 02:25

MongoDB等のデータベースを使用したPHPフレームワークが無いかと調べたところ、通称CakePHP3と呼ばれるフレームワークLithiumがあるのを知り、実際にインストールしてみる事にしました。

チュートリアル(ブログの様な記事投稿システム)もあるので今回実際に体験してみましたので、簡単に流れを記事にしました。

チュートリアル

http://rad-dev.org/lithium/wiki/drafts/blog-tutorial


環境

OS:CentOS5.4

PHP:5.3.1

MongoDB:1.2.2

Lithium:0.9



lithiumダウンロード解凍

最新版はlithium-0.9になりますね。

wget http://d10xg45o6p6dbl.cloudfront.net/projects/l/lithium/lithium-0.9.zip
unzip lithium-0.9.zip
mv lithium-0.9 lithium

apacheのドキュメントルート設定を、解凍したディレクトリ内にあるapp/webrootに設定します。

(apacheのrestartも忘れずに)

また、MongoDBインストールMongoDBプロセスも立ち上げておきます。


ブラウザからアクセスすると下記の画面が現れます。

f:id:camelmasa:20100420232348p:image


0.8と若干画面が変わりましたね。




チュートリアルその1

まず、さきほどの初期画面に表示されている指示に従います。

chmod -R 0777 /var/www/lithium/app/resources

その後チュートリアルに戻り下記のコマンドでphpからMongoDBを操作するプラグインインストールします。

sudo pecl install mongo

app/config/connections.phpに下記を追加します。

// MongoDB Connection
    Connections::add('default', array('type' =>  'MongoDb', 'database' => 'blog', 'host' => 'localhost'));

app/config/bootstrap.phpの46行目のコメントを外します。

require __DIR__ . '/connections.php';

すると初期画面が下記のようになり、初期設定が完了した事がわかります。

f:id:camelmasa:20100420232349p:image




チュートリアルその2

実際にMVCを作成するプロセスです。

まずはModelを作成します。

app/models/Post.phpを作成し下記の記述をします。

<?php
    namespace app\models;

    class Post extends \lithium\data\Model {
    }

これでModelの作成完了です。


次にControllerの作成です。

app/controllers/PostsController.phpを作成し下記の記述をします。

<?php
namespace app\controllers;
use app\models\Post;

class PostsController extends \lithium\action\Controller {

    public function index() {
        $posts = Post::all();
        return compact('posts');
    }
    public function add() {
        $success = false;
        if ($this->request->data) {
            $post = Post::create($this->request->data);
            $success = $post->save();
        }
        return compact('success');
    }
}

これでControllerの作成完了です。


次にViewを作成します。

まずブログの記事一覧を表示する、index.html.phpを作成します。

app/views/posts/index.html.php

<?php foreach($posts as $post): ?>
<article>
<h1><?=$post->title ?></h1>
<p><?=$post->body ?></p>
</article>
<?php endforeach; ?>

次にブログの書込み用の画面を作成します。

app/views/posts/add.html.php

<?php if ($success): ?>
<p>Post Successfully Saved</p>
<?php endif; ?>
<?=$this->form->create(); ?>
<?=$this->form->field('title');?>
<?=$this->form->field('body', array('type' => 'textarea'));?>
<?=$this->form->submit('Add Post'); ?>
<?=$this->form->end(); ?>

チュートリアル(その3)

MVCの作成は終わりました。

実際にブラウザからアクセスしてみたいと思います。

http://sample.com/posts/add

下記の様な投稿画面が表示されました。

綺麗なフォームが簡単に生成されるヘルパーの様ですね。

入力欄が大きいので、iPhoneからの投稿も楽でした。

f:id:camelmasa:20100423021622p:image


http://sample.com/posts

下記は記事一覧画面ですね。

f:id:camelmasa:20100423021623p:image



まとめ

Lithiumはファイル数やディレクトリの配置を見てとても軽量で薄い印象を受けましたが、それと同時にパワフルなフレームワークだなと思いました。

MongoDBを採用しているのも評価出来ます。

後は日本語のノウハウが欲しいところです!

時間がある時に少しずつ勉強していきたいと思います。

追記

mixiコミュニティを作成してみました。

情報交換したいです。

宜しくお願いしますー。

http://mixi.jp/view_community.pl?id=4975003



[PR]Spreeの情報を集めています。

ECを持ちたい方、仕事でECを使いたい方向けのコミュニティサイトです。

このサイトでは世界で最も使用されているECの1つであるSpreeについての情報を提供しています。

http://spreecommerce.jp/

2010-02-26

MongoDB,CouchDB,MySQL,memcacheデータをPHPから読み込み&書き込み速度を検証してみました!(その2)

| 13:16

前回、MongoDB,CouchDB,MySQL,memcacheの読み込み&書き込み速度を検証してみました。

MongoDB,CouchDB,MySQL,memcacheデータをPHPから読み込み&書き込み速度を検証してみました! - @camelmasaの開発日記

下記の原因で予想していたような結果を出す事が出来ませんでした。

MongoDBでコネクションプーリングをしていなかった。

・CouchDBのHTTPリクエスト方法が遅かった。

id:yssk22さんのコメントにより上記の部分を修正する事が出来ましたので再度検証してみました。


gt

CouchDB:0.10.1

MySQL:5.1.43

memcache:1.2.8

CPU:AMD(の何か)

メモリ:4GB

(ざっくり検証です。)



読み込み時のソース

前回と一緒で"test"データベースの"test"テーブル(コレクション)の"test"データをphpから読み込みするプログラムです。

couchdb.php

<?php

$ch = curl_init("http://192.168.0.30:5984/");
$fp = fopen("test/1ab25e328d1f36b2895671666491e48f", "w");

curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);

curl_exec($ch);

前回、PEARパッケージであるHTTP_Requestを用いて検証して物凄く遅かったのですが、cURL関数を使って通信する事で速度が飛躍的に向上する事が期待できます。


mongodb.php

<?php

$mongo = new Mongo();

$db = $mongo->selectDB("test");
$col = $db->selectCollection("test");
$cursor = $col->findOne();

前回コネクションプーリングしていなかったので今回はコネクションプーリングして検証します。

コンストラクタの第3引数にtrueをする事でプーリングを確保出来ます。


mysql.php


<?php
<?php
$link = mysql_pconnect('localhost', 'user', 'pass');
mysql_select_db('mytest', $link);
$result = mysql_query('SELECT `test` FROM `test` LIMIT 0,1;');

memcache.php

<?php

$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
$memcache->get('test');


読み込み結果

couchdb.php

ab -c 100 -n 1000 'http://192.168.0.30/couchdb.php'

Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /couchdb.php
Document Length:        41 bytes

Concurrency Level:      100
Time taken for tests:   3.152094 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      232000 bytes
HTML transferred:       41000 bytes
Requests per second:    317.25 [#/sec] (mean)
Time per request:       315.209 [ms] (mean)
Time per request:       3.152 [ms] (mean, across all concurrent requests)
Transfer rate:          71.70 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   7.9      0      31
Processing:    26  302 112.4    248     813
Waiting:       26  302 112.5    248     813
Total:         26  305 112.7    248     813

Percentage of the requests served within a certain time (ms)
  50%    248
  66%    262
  75%    349
  80%    443
  90%    515
  95%    525
  98%    534
  99%    538
 100%    813 (longest request)

mongodb.php

ab -c 100 -n 1000 'http://192.168.0.30/mongodb.php'

Benchmarking 192.168.0.30 (be patient)


Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /mongodb.php
Document Length:        0 bytes

Concurrency Level:      100
Time taken for tests:   1.404074 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      190570 bytes
HTML transferred:       0 bytes
Requests per second:    712.21 [#/sec] (mean)
Time per request:       140.407 [ms] (mean)
Time per request:       1.404 [ms] (mean, across all concurrent requests)
Transfer rate:          132.47 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   7.2      0      30
Processing:    10  129  88.5    124     844
Waiting:        9  128  88.4    124     843
Total:         29  131  88.9    124     865

Percentage of the requests served within a certain time (ms)
  50%    124
  66%    125
  75%    130
  80%    130
  90%    145
  95%    152
  98%    191
  99%    750
 100%    865 (longest request)

mysql.php

ab -c 100 -n 1000 'http://192.168.0.30/mysql.php'

Benchmarking 192.168.0.30 (be patient)


Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /mysql.php
Document Length:        0 bytes

Concurrency Level:      100
Time taken for tests:   1.533586 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      190000 bytes
HTML transferred:       0 bytes
Requests per second:    652.07 [#/sec] (mean)
Time per request:       153.359 [ms] (mean)
Time per request:       1.534 [ms] (mean, across all concurrent requests)
Transfer rate:          120.63 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    3   6.2      0      25
Processing:    13  142 125.8    135    1512
Waiting:        9  141 126.1    134    1510
Total:         20  146 126.1    138    1528

Percentage of the requests served within a certain time (ms)
  50%    138
  66%    147
  75%    149
  80%    151
  90%    155
  95%    159
  98%    165
  99%    182
 100%   1528 (longest request)

memcache.php

Benchmarking 192.168.0.30 (be patient)


Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /memcache.php
Document Length:        0 bytes

Concurrency Level:      100
Time taken for tests:   1.305582 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      190950 bytes
HTML transferred:       0 bytes
Requests per second:    765.94 [#/sec] (mean)
Time per request:       130.558 [ms] (mean)
Time per request:       1.306 [ms] (mean, across all concurrent requests)
Transfer rate:          142.47 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    4   6.7      1      28
Processing:    26  121  30.1    129     188
Waiting:       25  116  29.5    124     187
Total:         26  126  33.2    132     193

Percentage of the requests served within a certain time (ms)
  50%    132
  66%    141
  75%    148
  80%    153
  90%    164
  95%    171
  98%    179
  99%    183
 100%    193 (longest request)


読み込み結果検証

Time taken for testsが

memcache>MOngoDB>MySQL>CouchDB

の順番になりましたね。

これは納得がいく順番ですね。


前回同じ条件でのcouchdb.phpが9.587989 secondsでしたが、今回は3.152094 secondsと飛躍的に増加しました!

MongoDBをコネクションプーリングする事でも処理が早くなりました。

下記が接続時のログですが、1000回のアクセスにも係わらず21回しか新規の接続をしていない事が確認できます。

Fri Feb 26 12:25:52 db version v1.2.2, pdfile version 4.5
Fri Feb 26 12:25:52 git version: 8a4fb8b1c7cb78648c55368d806ba35054f6be54
Fri Feb 26 12:25:52 sys info: Linux domU-12-31-39-01-70-B4 2.6.21.7-2.fc8xen #1 SMP Fri Feb 15 12:39:36 EST 2008 i686 BOOST_LIB_VERSION=1_37
Fri Feb 26 12:25:52 waiting for connections on port 27017
Fri Feb 26 12:27:02 connection accepted from 192.168.0.30:51154 #1
Fri Feb 26 12:27:02 connection accepted from 192.168.0.30:51155 #2
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51156 #3
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51157 #4
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51158 #5
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51159 #6
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51160 #7
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51161 #8
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51162 #9
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51163 #10
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51164 #11
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51165 #12
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51166 #13
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51167 #14
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51168 #15
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51169 #16
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51170 #17
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51171 #18
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51172 #19
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51173 #20
Fri Feb 26 12:27:03 connection accepted from 192.168.0.30:51442 #21
Fri Feb 26 12:27:04 end connection 192.168.0.30:51161

次は書き込み時の検証してみます。



書き込み時のソース

couchdb_write.php

<?php

$ch = curl_init("http://192.168.0.30:5984/");
$fp = fopen("test", "w");

curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"test":"test"}');

curl_exec($ch);

mongodb_write.php

<?php

$mongo = new Mongo('192.168.0.30:27017',true,true);

$db = $mongo->selectDB("test");
$col = $db->selectCollection("test");
$col->insert(array("test" => "test"));

mysql_write.php

<?php
$link = mysql_pconnect('localhost', 'user', 'pass');
mysql_select_db('mytest', $link);
$result = mysql_query("INSERT INTO `test` VALUES ('test');");

memcache_write.php

<?php

$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
$memcache->set("test", "test");


書き込み結果

couchdb_write.php

ab -c 100 -n 1000 'http://192.168.0.30/couchdb_write.php'

Benchmarking 192.168.0.30 (be patient)


Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /couchdb_write.php
Document Length:        64 bytes

Concurrency Level:      100
Time taken for tests:   3.193331 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      255255 bytes
HTML transferred:       64064 bytes
Requests per second:    313.15 [#/sec] (mean)
Time per request:       319.333 [ms] (mean)
Time per request:       3.193 [ms] (mean, across all concurrent requests)
Transfer rate:          77.98 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   38  31.2     33     117
Processing:   110  268  92.0    239     561
Waiting:        3  237  90.8    217     537
Total:        112  306 106.7    275     642

Percentage of the requests served within a certain time (ms)
  50%    275
  66%    300
  75%    315
  80%    353
  90%    507
  95%    556
  98%    595
  99%    616
 100%    642 (longest request)

mongodb_write.php

ab -c 100 -n 1000 'http://192.168.0.30/mongodb_write.php'

Benchmarking 192.168.0.30 (be patient)


Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /mongodb_write.php
Document Length:        0 bytes

Concurrency Level:      100
Time taken for tests:   1.227498 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      190000 bytes
HTML transferred:       0 bytes
Requests per second:    814.67 [#/sec] (mean)
Time per request:       122.750 [ms] (mean)
Time per request:       1.227 [ms] (mean, across all concurrent requests)
Transfer rate:          150.71 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   11   7.7     11      30
Processing:    25  105  18.4    109     131
Waiting:        3   94  19.8     92     121
Total:         25  116  19.9    119     160

Percentage of the requests served within a certain time (ms)
  50%    119
  66%    126
  75%    131
  80%    133
  90%    138
  95%    141
  98%    145
  99%    150
 100%    160 (longest request)

mysql_write.php

ab -c 100 -n 1000 'http://192.168.0.30/mysql_write.php'

Benchmarking 192.168.0.30 (be patient)


Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /mysql_write.php
Document Length:        0 bytes

Concurrency Level:      100
Time taken for tests:   1.480484 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      190000 bytes
HTML transferred:       0 bytes
Requests per second:    675.45 [#/sec] (mean)
Time per request:       148.048 [ms] (mean)
Time per request:       1.480 [ms] (mean, across all concurrent requests)
Transfer rate:          124.96 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.6      0       9
Processing:     5  139  57.9    151     619
Waiting:        5  139  58.0    151     619
Total:          5  140  57.8    151     625

Percentage of the requests served within a certain time (ms)
  50%    151
  66%    154
  75%    155
  80%    157
  90%    186
  95%    213
  98%    224
  99%    332
 100%    625 (longest request)

memcache_write.php

ab -c 100 -n 1000 'http://192.168.0.30/memcache_write.php'

Benchmarking 192.168.0.30 (be patient)


Server Software:        Apache/2.2.3
Server Hostname:        192.168.0.30
Server Port:            80

Document Path:          /memcache_write.php
Document Length:        0 bytes

Concurrency Level:      100
Time taken for tests:   1.244228 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      190190 bytes
HTML transferred:       0 bytes
Requests per second:    803.71 [#/sec] (mean)
Time per request:       124.423 [ms] (mean)
Time per request:       1.244 [ms] (mean, across all concurrent requests)
Transfer rate:          148.69 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    8  10.6      1      37
Processing:    15  112  35.4    124     192
Waiting:        7  106  33.5    118     191
Total:         32  120  39.1    129     199

Percentage of the requests served within a certain time (ms)
  50%    129
  66%    143
  75%    150
  80%    156
  90%    165
  95%    175
  98%    185
  99%    190
 100%    199 (longest request)


全体を通したまとめ

書き込み時のTime taken for testsが

MongoDB>memcache>MySQL>CouchDB

の順番になりましたね。

こちらも納得がいく順番ですね!

MongoDB早いですね!!!流石です。

CouchDBはこれぐらいの速さなのですかね?

色々なドキュメントを見ると、MongoDBより遅いという記事を見ますが…。


あとがき

今度はこうしたらCouchDBが早くなるよ!的なアドバイス欲しいな〜。(あるかな?)

上記のテストサーバーは家でそのままにしてあるので、こんなテストして!っていう場合コメント下さい。

最後にid:yssk22さん有難う御座います!



[PR]Spreeの情報を集めています。

ECを持ちたい方、仕事でECを使いたい方向けのコミュニティサイトです。

このサイトでは世界で最も使用されているECの1つであるSpreeについての情報を提供しています。

http://spreecommerce.jp/

yssk22yssk22 2010/02/27 01:34 あ、pconnect を前提にやるんですね。
であれば、CouchDBは HTTP Keep-Alive ヘッダーを使って connection pooling すれば性能は上がると思います。
PHP の cURL ライブラリでできるかどうかはわかりませんが。
# というか、socket reuse でここまで変わるんですね < Mongo

>色々なドキュメントを見ると、MongoDBより遅いという記事を見ますが…。
多くのベンチマーク記事をみてきましたが、こういうテストケースの場合は、CouchDBとMongoDBのアーキテクチャーを考える、仕方ないかなぁ、と思います。システムワイドでみれば、逆転するケースもあります。

camelmasacamelmasa 2010/04/03 23:33 返信が遅くなりました。
すみません。

なるほど!

CouchDBはKeep-Aliveでプーリング出来るんですね!
次時間ある時検証してみたいと思います。

通りすがり通りすがり 2011/09/26 15:51 面白かった。自分もテストしたけどだいたい似たような感じでした。
ちなみに、mysqlはlocalhostで接続すると少し有利、127.0.0.1でやると他と同じ条件になるかも?
あと自分はネットワーク経由で別サーバへ接続するテストだったのですが(その方が実環境に近いので)この場合はプーリングの効果は非常に大きくなります。memcachedよりも速くなることもあります(mongodbはもちろん速い)
ちなみに、mongodbの書き込みはオプションがあって、デフォルトは書込んだかどうか確認しないので非常に速いです(Webの負荷も低い)でも通常は書込んだことを確認するオプションをつけると思うので意味がないです(ログをmongodbへ記録するような用途には使えるが)