Node.jsの動く仕組み



IIJ 大津繁樹

2011年12月16日

このプレゼン資料は http://ohtsu.no.de/ にあります。

FireFox4以上/Chrome 限定です。話者と共にスライドが動きます。

プレゼンで「へぇ~」と思った時は、左上の「へぇ~ボタン」を押して下さい。

Node.jsとは、


サーバサイトJavaScript

フレームワーク? プラットフォーム? プログラミング環境?

「Nodeのゴールはノンブロッキングなネットワークプログラミングをサーバ開発に熟知していないユーザにも可能にすることです。」by Ryan Dahl (creater of Node.js)

正式名称は Node で、他と紛らわしく区別したい時に Node.js と呼ぶらしいです。

Node の歴史

  • 2009年2月から Ryan Dahl が開発開始(当時フリーのプログラマー)
  • 2009年5月 node-0.0.1 リリース(first release)
  • 2010年4月 HerokuがNode.jsの実験サポートを開始
  • 2010年8月 node-0.2.0 リリース(first stable)
  • 2010年11月 Node の開発が Joyent に移管。
  • 2011年2月 node-0.4.0 リリース
  • 2011年11月4日 node-0.6.0リリース (Native Win/Clusterサポート)
  • 2011年12月16日現在 node-0.6.6
次の安定版は2012年1月リリース予定。今後ChromeやV8と合わせて6週間周期のリリースを目指す。

http://nodejs.orgでソース(tar.gz)/Win msi/Mac pkgがダウンロード可

Nodeの開発

GitHub上で行われています。https://github.com/joyent/node

ちなみに私もAuthorの一人(メールアドレスがぁ…)

doc typoの一字修正でも merge されればAuthorに入れてもらえますので開発に協力しましょう。

Nodeの特徴(*)

  • ノンブロック・非同期I/O : 後述
  • JavaScript: Chrome実装のV8エンジン
  • Single Process/Single Thread(**): 500~1000同時接続でも200Mbyte程度の省メモリ(***)の実績。C10K対応
  • エコシステムと各種: npm+express,socket.io,jsdom

日本ではアメーバピグライフで使われているのが最大か。(20台で320 Node.js 同時20万接続) http://www.slideshare.net/snamura/nodejs-9956558

(*) 別に世の中で Node だけが実現できている機能じゃありません。(念のため)
(**) 実は libeio で threadを4つ使っています。
(***) node-v0.6からcluster を使って multiproces, v0.8から V8 isolate を使って muliti thread 対応

ノンブロッキング・非同期



レジで注文・すぐ支払。後でコーヒーできたら呼び出されて受け取る。

詳しいことは kazu さんの TechWeek 2011 の資料参照

Bad Use Cases

CPU heavy apps

CPU利用が重くとI/Oが軽いアプリは Node.jsにはあわない。

ビデオエンコーディング・AI・その他CPUを食いつぶすソフトに Node.jsを使わない方がいい。 多少工夫しても C や C++でやった方がいい結果がでる。

Node.jsには C++ アドオンが用意できるので、CPUヘビーなアプリをC++アドオンにしてスクリプトエンジンとしてNode.jsで使うこともできる。

Felix's Node.js Convincing the boss guideより翻訳

Bad Use Cases

Simple CRUD/HTML apps

Node.jsはいろんなWebアプリケーションを作るのに面白いツールかもしれないが、PHP,Ruby,Python以上のものを求めてはいけない。 Node.jsを使えば多少はスケーラブルになるかもしれないが、単に Node.js で書いたからといってトラフィックが魔法のように増加するわけではない。

また、Node.jsでよくできたフレームワークからスタートしたとしても Rails/ CakePHP/ Djangoなどにはまだ及ばない。

データベースのデータから単純にHTMLをレンダリングするようなアプリを Node.js で実装しても実質的なビジネス利点はほとんどない。

Bad Use Cases

NoSQL + Node.js + Buzzword Bullshit

時期アプリのアーキテクチャを Node.js と NoSQLを組み合わせて設計しようとしているならちょっと待った方がいい。

Redis, CouchDB, MongoDB, Riak, Casandra等は本当に魅力的だが、禁断の果実になっていないか?

既にNode.jsを使うことで技術リスクを負っているのに、さらによく知らないNoSQLを使ってそれ以上のリスクを抱える必要はあるのか?

Good Use Case


JSON API

軽量な REST/JSON APIを作るのにNode.jsを使うのはぴったり。 JavaScriptと組み合わせた non-blockingモデルを使うことによって、Node.js は他のデータベース・Webサービスのデータソースを隠してJSONインターフェイスを提供するといった目的には良い選択になります。

Single page apps

GMailのような重い Ajaxを使う単一ページの作成を予定しているなら Node.js はよく合うだろう。 短いレスポンス時間で多くのリクエスト/秒を処理する能力は、サーバとクライアント間でデータが共有できる ことと相俟って Node.jsはクライアントで多くの処理を行うモダンWebアプリにとって非常に良い選択です。

Good Use Case


Shelling out to unix tools

Node.jsはまだできたばかりなので足りないソフトをいろいろ再発明したくなるが、既存のコマンドラインツールの領域に打って出るのも一つの手である。 Node.jsは何千もの子プロセスを spawn() して、その出力をストリームとして扱えるので、既存のソフトを利活用したいと思っている人には理想的な選択肢にもなる。

Streaming data

従来のWebスタックは普通 http request/response をアトミックイベントとして扱ってきたが、ストリームの場合は当てはまらない。 Node.jsアプリではそういう場合でも利点を持っている。一つの例としてファイルアップロードの parse をリアルタイムで行うことである。 異なるデータレイヤーの間で proxy を構築することと同じである。

Good Use Case


Soft Realtime Application

Node.js ではリアルタイムのソフトを簡単に作ることができる。 twitter、チャットアプリ、スポーツ賭アプリ、インスタントメッセージネットワークへのインターフェイスなどである。 だけどJavaScriptは動的にGCを行う言語であることに注意してほしい。 GCがどれだけの頻度でどれだけ長く行われるかでレスポンスタイムが変わってしまう。 なので Node.js で一定のレスポンスタイムを要求する厳しいリアルタイムシステムを作ろうとしてはいけない。 その場合 Erlang が良い選択肢であろう。

Nodeのアーキテクチャ


libuvで何ができる?


  • ノンブロッキング TCPソケット(Windows IOCP利用)
  • ノンブロッキングnamed pipes
  • UDP
  • タイマー
  • 子プロセスの spawning (fork&exec)
  • c-ares や uv_getaddrinfoを使ったDNS
  • 非同期ファイルシステムAPI uv_fs_*
  • 高精度(ナノ秒)時間 uv_hrtime
  • カレント実行パス取得 uv_exepath
  • スレッドプールスケジューリング uv_queue_work
  • ファイルシステムイベント(RENAME/CHANGE) uv_fs_event_t
  • VT100 TTY uv_tty_t (stdin/stdout/stderr)
  • IPC and socket プロセス間共有 uv_write2

Hello UV


libuvは Node 以外でも使えます。 https://gist.github.com/1321702

#include <stdio.h>
#include "uv.h"
static void cb(uv_write_t* req, int status) {
  printf("Hello from Callback.\n");
  uv_unref(uv_default_loop());
}

int main() {
  uv_tty_t tty;   // tty stream handle
  uv_write_t req; // write request
  int ret = uv_tty_init(uv_default_loop(), &tty, 1, 0);
  uv_buf_t bufs[] = { uv_buf_init("Hello UV!\n",10) };
  ret = uv_write(&req, (uv_stream_t*)&tty, bufs, 1, cb);
  uv_run(uv_default_loop());
  return 0;
}

Node のしくみ



Moduleのしくみ


Node.js Module読み込みの疑似コード

function Module() {
  this.exports = {};
  ...
}
Module.require = function(id) {
  var module =  new Module(id);
  (function (exports, require, module) {
     モジュール内コード
     exports = ... 
  })(module.exports, Module.require, module);
  return module.exports;
}
// こっから本体     
var require = Module.require;
var hoge = require("モジュール名");

Moduleサンプル(JS)

モジュール:./hoge.js

  exports.foo = "foo";

実行する JSファイル run.js

  var hoge = require("./hoge.js");
  console.log(hoge.foo);

実行結果

> node run.js
> foo

Moduleサンプル(C++)


void Work(uv_work_t* req) { ... }
void Done(uv_work_t* req) {
  HandleScope scope;
  Local<Value> argv[1] = {Local<Value>::New(String::New("Work Done"))};
  callback->Call(Context::GetCurrent()->Global(), 1, argv);
  callback.Dispose();
}
Handle<Value> putQueue(const Arguments& args) {
  HandleScope scope;
  callback = Persistent<Function>::New(Local<Function>::Cast(args[0]));
  int status = uv_queue_work(uv_default_loop(),&request,Work, Done);
 return Undefined();
}
void RegisterModule(Handle<Object> exports) {
  exports->Set(String::NewSymbol("putQueue"),
    FunctionTemplate::New(putQueue)->GetFunction());}
NODE_MODULE(thread_test, RegisterModule);

Moduleサンプル(C++)


C++モジュールのビルド

> node-waf configure build
Setting srcdir to : /home/ohtsu/tmp/thread_test
...
'build' finished successfully (0.038s)  

実行JS run.js

var thread_test = require('./thread_test.node');
thread_test.putQueue(function(msg) {
  console.log(msg);
});

実行結果

> node run.js
>'Work Done'

Hello World

ということで Hello World サーバはこれ。

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(80);

node-v0.4.xでのシーケンス図(結構複雑です。) helloworld_node.pdf

My作品紹介

Node Neko


http://ohtsu.node-ninja.com/

おわり

御清聴ありがとうございました。

このプレゼンは、

0へぇ~」

でした。

(0/20)
0へぇ~

閲覧中