Archive

Posts Tagged ‘mongoDB’

マニアックな金融系サイトをnode.jsとMongoDBで実装してみた(実装編)

1月 19th, 2011

さて、前回の記事「マニアックな金融系サイトをnode.jsとMongoDBで実装してみた(概要編)」に続き、実装の詳細を書こうと思うのですが、こちらはどうせ技術者しか見ないので手っ取り早く、コードとシェルを中心にします。

この記事では、開発から運営まで一連の流れを示して、node.jsとMongoDBである程度のWebサービスを提供できるようになること、を目的としています。

SakuraのVPSにMongoDBとnode.jsをインストール

以前、別のサーバーにMongoDBを入れてアクセス解析をしようとしたのですが、どうやら32bit版だと1つのDBは2GB以上入れられないらしく。
しかたなしにSakruaのVPS(CentOS64bit)に64bit版のMongoDBをソースコードから入れました。
※32bitだとyumとかapt-getとかで入ったのにー

wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-1.6.5.tgz
tar xvzf mongodb-linux-x86_64-1.6.5.tgz
sudo mv mongodb-linux-x86_64-1.6.5 /usr/local/bin # どっか適当に
sudo mv /usr/local/bin/mongodb-linux-x86_64-1.4.3 /usr/local/bin/mongodb
useradd mongodb
mkdir /var/lib/mongodb  # 中身を入れるディレクトリ
chown -R mongodb:mongodb /var/lib/mongodb
mkdir /var/log/mongod
chown -R mongodb:mongodb /var/log/mongod
sudo /sbin/chkconfig --add mongod
/sbin/chkconfig mongod on
/sbin/chkconfig --list |grep mongod
sudo /etc/init.d/mongod # 起動スクリプト
sudo /etc/init.d/mongod start
sudo easy_install pymongo # ついでにpythonから使うのでライブラリインストール

ちなみに、デーモン化したかったので簡単な起動シェルをこちらから拝借してきました。
» 技術メモ
(こちら、公開してなかったらゴメンナサイ。そしたら別にファイル作ります。)

試しにmongoのシェルから動いてるのを確認してみてください。

mongo
----
MongoDB shell version: 1.6.5
connecting to: test
> show dbs
admin
local
test

次にnode.jsを入れます。
安定版の0.2.6をインストール。ssl使う場合はもっと大変そう。

wget http://nodejs.org/dist/node-v0.2.6.tar.gz
tar zxvf node-v0.2.6.tar.gz
cd node-v0.2.6
./configure --without-ssl
make
sudo make install

また、node.jsはライブラリのパッケージ管理にnpmというものを使っていて、こちらもインストール。

ここまできて、npmは/usrとか/usr/localにroot権限で入れるのではなく、$HOME/.npmrcを設定して一般ユーザーの権限で入れるのがベストプラクティスなのだと理解した。
» npmをインストールする – スコトプリゴニエフスク通信

とのことで、おとなしくそれに従う。ってか実際rootで入れると、sudo npm install xxxするときに怒られます。

wget https://download.github.com/isaacs-npm-v0.2.14-6-14-g0cec5bf.tar.gz
cat >>~/.npmrc <<NPMRC
root = $HOME/.node_libraries
binroot = $HOME/bin
manroot = $HOME/share/man
NPMRC
tar -zxvf isaacs-npm-v0.2.14-6-14-g0cec5bf.tar.gz
cd isaacs-npm-v0.2.14-6-14-g0cec5bf
make install

で、必要なライブラリをインストール。

npm install express # これは古いらしく結局ソースから読み込み・・・
npm install mongodb
npm install ejs
npm install spark # 結局使わず・・・
npm install forever

node.jsでwebサーバーを書く

これで一通り環境が整ったので、適当なフォルダにapp.jsかなんかのファイル名でごりごり書いていきます。
前提として、mongoDBに既に必要なデータは入ってるものとします。
詳しくはmongoDBの日本語マニュアルを参照。@doryokujin君に感謝!

ちなみにnode.jsコミュでは一番メジャーっぽい、express.jsっていうフレームワークを使っています。
githubにサンプルコードがたくさん載っていて、特にmvcがとても参考になりました。

なお、フォルダ構成はこんな感じです。
/service
 /public・・・cssとかimgとか静的ファイル
 /express・・・expressの本体
 /views・・・テンプレートファイル
  body.html
  layout.html
  header.html
 app.js

app.js

var express = require('./express'),
	phpjs = require('./php');

var app = module.exports = express.createServer(),
	Db = require('mongodb/db').Db,
	ObjectID = require('mongodb/bson/bson').ObjectID,
	Server = require('mongodb/connection').Server,
	db = new Db('dbname', new Server('localhost', 27017, {}));

app.set('views', __dirname + '/views');
app.register('.html', require('ejs'));
# express.jsはテンプレートエンジンにjadeを使ってるがキモいのでejs
app.set('view engine', 'html');
app.use(express.staticProvider(__dirname + '/public'));
# 静的フォルダの指定
app.use(express.logger('\x1b[33m:method\x1b[0m :date :status \x1b[32m:url\x1b[0m :response-time :remote-addr :referrer'));
# loggerはnode.jsが使っているConnectのformatに対応
app.helpers({ # テンプレートから呼び出せるヘルパー関数群
  helper1: function(){ return false; },
  helper2: functoin(){ return true; }
});
# routingの部分。 / にアクセスしたらこれが実行される
app.get('/', function(req, res){
	getCollection1(function(result1){
		getCollection2(function(result2){
			res.render('body', { # layout.htmlを使ったbody.htmlを描画
				layout:'layout',
				result1: result1,
				result2: result2
			});
		});
	});
});

db.open(function(){}); # dbをオープン。これしないと接続できなかった。。。
function getCollection1(callback) {
	db.collection('collection1', function(error, stock_info) {
		if( error ) console.log(error);
		else {
			stock_info.find({}, function(error, cursor){
				if( error ) console.log(error)
				else{
					cursor.toArray(function(error, results) {
						if( error ) console.log(error)
						else callback(results);
					})
				};
			})
		}
	});
}
function getCollection2(callback) { /* 以下同文 */ }

console.log('Express app started');
app.listen(3000);

layout.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
	<div id="header"><%- partial('header') %></div><!-- こういう風にヘッダも分けれる -->
	<div id="body"><%- body %></div><!-- 中身がここに書かれる -->
</body>
</html>

開発のポイントとしては、
php.jsが便利すぎる!
 phpの関数をjavascriptでどう書くか?というスニペット集。
 上記コードでは必要な関数を外部モジュール化して使ってます。
loggerのformatが不明だった
 node.jsが使っているConnectのサイトにAPIが!
DBへのアクセス毎にcallbackが入れ子していくので、とにかくアクセスは少なく!
 いやはやMongoDB使ってて正解でした。
 これがMySQLだったらどれだけ入れ子していったことか。
 もちろんjsdeferredとか使って同期処理させることはできますが。

これでモノは揃ったので、実際に実行してみます。

cd /path/to/service
node app.js

すると”Express app started”と出るので、実際に http://localhost:3000/ から確認してください。
ポートは自由に変えられます。

nodeのデーモン化を行う

一応以上までで実装は完了してるのですが、これをちゃんとサービスとして運営するにはあともろもろ必要ですよね。

一番てこずったのが、デーモン化。
なんかエラー出して止まっちゃったときに、自動で再起動してくれないと困る。
結論から言うと、npmでインストールできるforeverというライブラリを使っているのですが、右余曲折ありまして。

1. どうやらspark(configの設定、マルチコア対策)+upstart(デーモン化)+monit(監視)がテッパンらしい。
» Deploying Node Apps with Spark – How To Node – NodeJS
» Deploying Node.js With Upstart and Monit
2. sparkはすんなり入った。
3. upstartが動かん・・・ってrequirementがpython2.5以上で他にもCentOS5向けじゃなさそう・・・
» What are the requirements for building Upstart?
4. じゃあmonitから直でspark呼ぶか、ってnpmとか諸々$HOMEに入れてるから、monitから起動できない模様・・・
5. なんか他にも、spark2とかdaemon.nodeとかforeverとか色々あるな~
6. daemon.nodeは割と有名っぽいけど、作者が同じforeverが簡単そう!

cd /path/to/service
forever start app.js

7. 動いた!←イマココ

これで何とかデーモン化ができました。

実際にデプロイする

ちょっとポートを空けてうんぬんとか面倒くさかったので、ApacheからProxyさせました。
これだとloggerの:remote-addressにIPが出ないんですけどね・・・
近々改善予定。
» mitukiii.jp | Ubuntuにnode.js入れてApacheからProxyさせてみた

ついでにMongoDBの状況をmuninでチェックできるように、mongo-muninとやらを導入しました。

sudo ln -s /usr/share/munin/plugins/mongo_ops /etc/munin/plugins/mongo_ops
sudo /etc/init.d/munin-node restart

まとめ

いやいや、MongoDBもnode.jsも初めてだったので四苦八苦しました。
しかもnode.jsに関しては、まとまった日本語ドキュメントが無いという・・・
ていうか全体的にドキュメントが不足がち。
しかもまだ安定運営周りの方法が確立していないようで、色々議論されてました。
node servers, npm scripts, spark2 and monit
たしかにnpm start app.jsで管理できたら便利やなー

でもこれで、一通りnode.js周りのことが勉強できたし、足りないとこだらけなので貢献していければなーと思います。
久々の長文ありがとうございました。

今回リリースしたサイト↓
http://marketgeek.net/ja/

8maki IT, proposal, エンジニア, サービス , ,

マニアックな金融系サイトをnode.jsとMongoDBで実装してみた(概要編)

1月 19th, 2011

ちょっと半分趣味で、Marketgeekなるマニアックなファイナンス系のサイトを、意味もなくnode.jsとMongoDBで実装、リリースしました。

ただ、node.jsとMongoDBは結構はやりな割に、運用実績がすごく少ないようで、その技術の背景など含めてまとめてみました。
※なお、開発回りのことだけ知りたい方はこちらへどうぞ↓
» マニアックな金融系サイトをnode.jsとMongoDBで実装してみた(実装編)

node.jsとは何か?

node.jsは、サーバーサイドJavascriptのフレームワークで、簡単にWebサーバー等を実装することができます。

サーバサイドJavascriptは昔から注目されていましたが、node.jsの登場で一気にその流れが加速。
理由といえば、こういう類のモノにしては、びっくりするくらい速い!こと。
Google Chromeで採用していたV8をJavascrptエンジンに使っており、スピードUPが測れたとのこと。
いわゆる”Pythonより速い”らしいw

加えて、昨今HTML5も騒がれていますが、そうなるとサーバーへのリクエストが細分化されますよね?
そうすると非同期で処理するnode.jsはうってつけかも!という流れもあり(WebSocketとか)、今年はnode.jsの年!と言われるようになったのかも。

node.jsに関してはこの記事が詳しいです↓
» 2011年はサーバサイドJavaScriptの年になる - Publickey

MongoDBとは何か?

MongoDBとは、いわゆるNoSQL系のDBで、最新DBの中では一番注目されているオープンソースです。
今まで主流のDBであるRDBは、いわゆるExcelのようにまず列を決めてその属性群(スキーマと言う)をもったデータを行として入れていく、というスタイルのものでしたが、NoSQL系のDBではkey(IDのようなもの)でデータを管理し、そのデータの属性(スキーマ)は一定に決めなくてもよい、という柔軟なデータ構造を取れるため各所で使われ始めています。
スキーマレスDBとも言われています。

中でもMongoDBは、KVS(Key Value Store)だけでなく、複雑な検索を行ったり、インデックス張ったり、簡単にスケールさせられたり(サーバー増やしやすい)と、実用にかなった機能をもっているため広まってきています。

ちなみに実用実績としては、ForsquareがMongoDBを採用してるようです。
MongoDBと他のDBとの比較はこの記事が詳しいです↓
» MongoDB’s performance as compared to others

また、3月頭にMongoDBの商用サポートを行っている10genのイベントが東京であるらしいので興味ある方はどうぞ。
» Mongo Tokyo

なぜnode.js+MongoDBを使って実装したのか?

柔軟に金融情報を管理しようとするとスキーマ決めるのって難しいよねーっていう感じと、今後もっとリッチなVisualizationを作っていくためにAjaxとかWebSocketに適してるっぽいのがいいという勘で、MongoDBとnode.jsを選んでみました。

。。。正直あんま理由とかはないですけどねf^^;
ていうか、もともとこういうサイトを作る気合いはあったのですが、ただ技術的には何も新しい・難しいことはないので、だったら勉強がてらやってみよう!というノリでw

あと、オープンソースコミュニティにもそろそろ絡んでいきたいなーと思っていて、発展途上のnode.jsとMongoDBは最適だ思ったので。
開発して分かったのですが、まだまだ色々な問題点があるので、随時コミットしていきたい。

なぜMarketgeekを作ったのか?

日本のベンチャー界隈も「世界へ出ろ!英語化しろ!」とはやし立てられてますけど、実際世界と日本の違いをまともに話せる人、まともに比較できるリソースがあまりにも少なすぎるかなー、と。
それだと「とりあえず英語化して、海外視察して、ちょっと英語でプレゼンしてみて。」っていう感じで終わってしまう気がする。
そこで、具体的に何を目標にどうアプローチしていけばよいのか、思考のネタになるものを作ってみたかったとです。

加えて、逆に英語圏の人からアジアのベンチャーとかって、中々見えにくいのではないでしょうか?
2バイト文字ばっかだし。
もちろん中国とかシンガポールとかにたくさんVCは進出してきてある程度情報が海を越えてるかもしれませんが、英語で書かれた米メディアに比べて、アジアの英語メディアって圧倒的に少ない。
特に東南アジア。
これからはアジアの時代になると言われていますし、思った以上にニーズがありそうで、かつそれなりのポジションを築けそうだったのでホイホイ作ってみました。

まぁなにより作ってて単純に楽しかったです。
最先端の技術使って、興味のあるマニアックなもの作ってw
Naspersって2兆円もあるのか!フヒヒヒヒヒっwwwみたいなw

あ、ちなみにNaspersは@anritさんが作ったこの図が凄く分かりやすい。
Zynga、Groupon、Facebookの金の供給元ってすごいですよね。
naspers

とりあえず見てみてください。随時機能拡張予定です。
http://marketgeek.net/ja/

あと、要望とかコメントとかあったらtwitterへどうぞ⇒@marketgeek_net

技術編はこちら↓
» マニアックな金融系サイトをnode.jsとmongoDBで実装してみた(実装編)

8maki IT, proposal, エンジニア, サービス, 金融 , , , ,