以下斜め読んだ内容

pseudo translation of useful posts, book reviews, remarks,etc. twitter: feeddict

Simon Willison「Node.jsは超エキサイティング」

Simon Willisonによる2009.11.23のブログエントリ

Node.js is genuinely exciting

Node.jsの詳しいレビュー。速い理由はV8だけじゃない、等々勉強になる。

以下斜め読んだ内容

Evented I/Oとは?

  • イベントドリブンなサーバーは、従来のスレッド/ブロックメカニズムへのオルタナティブ
    • スレッド/ブロックメカニズムはサーバーサイドプログラミングで主流
  • おさらい:よくあるWebフレームワークの動き
    • 利用できるサーバーのスレッド・プロセスからの命令で、少数のリクエストを同時にさばく
    • 長時間かかる処理は利用できるスレッド1つと結びつく
    • 利用できるスレッドがなくなればサーバーは応答しなくなる。
    • 大規模なトラフィックをさばくときは、できるだけ早く処理して、割り当てたスレッドを開放して、順番待ちしてる処理へ渡さないといけない
  • よくあるWebフレームワークで対応が難しいところ
    • サイズ大なファイルをアップロードしてアップロードしたファイルと複数のAPIから引っ張ってきたリソースと結びつける(APIの応答時間は予測できないものとする)
    • comet使って次のイベントが利用可能になるまで接続を開き放しにする
  • イベントドリブンプログラミングでは、ネットワークサーバーがI/O周りの処理がが完了するまで待機していることを利用する
  • メモリ上のデータへの処理は超速いが、ファイルシステムへのアクセスやネットワークをまたぐような処理は、レスポンスに時間がかかる。
  • Twisted/EventMachine/Node.jsがやってること
    • コールバックとリンクしたI/O周りの処理を特定していく
    • 単独のイベントループがタスクのリストの中で素早く切り替え、I/O処理を発火させ、次のリクエストをさばけるように移行する
    • I/Oが返ると、特定のリクエストの実行が再度ピックアップされる

イベントドリブンなフレームワークが既にある。Node.jsのどこがエキサイティングか

  • javascript
    • コールバック扱うのが得意な言語
    • イベントドリブンなプログラミングが当たり前になってる言語
  • しがらみゼロ
    • Twisted(Python)やEventMachine(Ruby)は大変
      • I/Oブロックするライブラリと一緒に使わないといけない
      • 使える/使えないライブラリについて勉強しないといけない
    • Node.jsではゼロからスタートして、I/OブロックするAPIは「ゼロにする」という設計でやってる
  • 軽量
    • APIのドキュメント30分くらい読んだら大体のアイディアが掴める規模。
  • 速い
    • V8使ってるから速い
    • 高速なI/Oライブラリlibio(Cライブラリ)と高速のイベントループライブラリlibev(Cライブラリ)使ってるから速い
      • libio/libevはMark Lehman謹製
    • スピードに異常にこだわるRyanは、オリジナルのHTTPパーサーを「C言語でハンドコーディングして」書いた
      • CのhttpパーサーはRagel/Mongrelが作ったもので結構速いのに、それを上回るのを作った。
  • すぐ始めれる
    • Nodeは必要モジュールが全部まとまってる。Snow Leopard上でカンタンにコンパイルできる

Node.jsを動かす

  • 割愛(git cloneからmake、等々)

Node.jsでHello World!

var sys = require('sys'), 
  http = require('http');

http.createServer(function(req, res) {
  res.sendHeader(200, {'Content-Type': 'text/html'});
  res.sendBody('<h1>Hello World</h1>');
  res.finish();
}).listen(8080);

sys.puts('Server running at http://127.0.0.1:8080/');

Macbookでベンチマーク取った(要 Apache Benchのインストール)

ab -n 1000 -c 100 'http://127.0.0.1:8080'
  • 同時接続100で1000回リクエスト出すテストして、1秒に3374リクエストさばいた
  • 改変してsetTimeout使ってリクエストを2秒後ごとに設定しても、1秒に50リクエストさばく。結構優秀
  • .finish()重要
    • リクエストされた処理が完了したことを明示的にシグナルを出し、ブラウザに戻るべきだと伝えてる
    • .finish()によって、cometライクなlong-polling/streamingの実装がとてもカンタンになってる
  • Node.jsのコアAPIは低レベル
    • httpクライアント/サーバー
    • DNSハンドリング
    • 非同期ファイルI/O
  • Node.jsは高レベルAPIを提供しない
    • Node.jsで動く軽量フレームワークが各所で量産されるという流れを生んだ
      • Node.jsで動いているウェブアプリのリスト見ろ
    • 大量発生したフレームワークを使って遊ぶのは、Node.jsの低レベルAPIを勉強する近道

作ってみた:djangode

  • Node.jsにURL操作機能を拡張
    • Djangoで使ってる正規表現を使ったURLハンドリングをしてる
    • まだプロトタイプ。Node.js触ってみたアイディア浮かんだら追加していく

作ってみた:nodecast

  • あとでかく

データベースの操作

  • nodecast自体ではメッセージはメモリ上に配列使って保存。
    • じゃあ、データの永続性はどうなってる?となる
  • データの永続性についての手っ取り早い解決は、NoSQLç³»
  • Node.jsのI/Oブロックしないという設計は、通常のデータベースライブラリと相性悪い(不可能じゃないが)
  • 通信プロトコルはシンプルがいい
    • (固有プロトコルじゃなく)TCP/IP上に実現されるシンプルなプロトコル使えるデータベース
    • もっといいのは、プロトコルがHTTP使うデータベース
  • NoSQL系のCouchDBとredis使ってみたが、動作はとてもよい
    • CouchDB用のクライアントで使ったのはnode-couch
    • redis用クライアントで使ったのは、redis-node-client
  • 自分が作ったnodecastではredisにメッセージキューが保存されてる。
    • データベースへ保存する動作書いたコードの部分は、コールバック使った、I/Oブロックしないデータベースインターフェースのいい見本になってると思う
  • MySQLã‚‚PostgreSQLもちゃんと使える
    • PostgreSQLはRyan謹製のNode.js製クライアントあり
    • MySQLは少し面倒
      • Node.jsが正式対応するには、独立したスレッドプールを作り、正式なクライアントライブラリへ統合していく必要あると思う
      • とりあえず、DBSlayerが提供してるhttpインターフェースを使ってMySQLへアクセスできる

Mixed Environments

  • Node.jsに開発を完全移行はまだしないけど
  • 従来のサーバーサイドプログラミングとNode.jsベースの開発の共存はできる
    • Node.js用にサブドメイン切るとか
    • プロキシサーバーの後ろで従来のサーバーとNode.jsサーバーを動かす