Home > IT, proposal, エンジニア, サービス > マニアックな金融系サイトをnode.jsと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/

Similar Posts:

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