Node.jsの第三歩:ノンブロッキングI/O事始め
前の日記: Node.jsの第二歩:便利そうなモジュールを追加インストール - くたくたシェルのブログ で参考にした記事で、「シングルスレッドでノンブロッキングI/Oなのはマルチスレッドとは違う」という旨が書かれていたが、非同期処理とどう違うのかなと違和感を覚えていた。そうしたら、後日解説記事があった:
要するに、非同期処理のことらしい。
イベントループを回している処理を担うスレッドが1つというだけで、全体としては並行処理しているわけだから、「シングルスレッド」にこだわる必要はなさそう。モデルの上では、並行処理が可能であればよいわけで、実体はマルチスレッドあるいはマルチプロセスでもいいわけだ。バックグラウンドジョブとしてプロセスを起動して、ループを回して処理を担う、たとえばスケジューラのようなスクリプトと処理形態は似ている。
なお、解説の中で、
そのため、ログの順番は、「start」「end」「response end」の順になります。
とあるのだが、おそらく必ずしもそうはならないのではないか?startは最初だとしても、endとresponse endの順序は保証されない、ということなのだと思う。
注意点は2つあるとのことで、
- コールバック関数の中でレスポンスの返し忘れがあると、処理をブロックしてしまう。(ここでいうブロックとは待ち状態になること?)また、別のクライアントからの要求が来ても並行して延々と待ち続けてしまい、イベントキュー?相当のリソースを食いつぶしてしまう。ただし、タイムアウトによりリソースが解放されるなら話は別だが、度を越すと 503 Service Unavailableなどになるリスクが残ることに変わりはない。
- レスポンスを返す役割を担うコールバック関数よりも先にレスポンスを返してしまうと、期待するレスポンスが返されない。
重たい処理はバックグラウンド処理(コールバック関数)にやらせておいて結果を後で取り出す必要が生じる。その仕組みとしては WebSocket, Commet, Ajax があるとのこと。
- Commet(コメット)はレスポンスをすぐに返さずにリクエストを保持しておき、イベントが起きてから返すことらしいのだけど、これって要するに普通のHTTP リクエスト&レスポンスとどう違うのかな?そもそもあまり聞かない用語。プッシュ型?タイムアウト相当の概念がないと大量同時接続時にリソースがパンクするのが目に見えている怖いアプローチじゃないかと思われます。
- Ajax を使う方法は要するにpollingするということなので、あまりやりたくない。せめて回数制限(タイムアウトに相当)をつけておかないと実際の運用で困りそう。(サーバー、ネットワークのリソース・負荷の面で)
そういうわけで、Node.jsでノンブロッキングなコールバック関数とイベントハンドラを慎重に書いたあとは、WebSocketですかね。
Node.jsの第二歩:便利そうなモジュールを追加インストール
前の日記: Node.jsの第一歩:インストールしてみた - くたくたシェルのブログ からの継続。参考サイトを頼りに、まずは言われるがままにやってみる。
今回の参考サイト
今回に限らず、今更なのだが、参考記事が書かれた日よりだいぶ年月が経っている。
私が導入した際に確認したバージョンは次の通り:
$ node -v
v0.12.7
$ npm -v
2.11.3
リンク切れも時折見られるがまだまだ情報としては現役。
NPMの本家サイトも充実しており参考記事によると1200超のパッケージがあるとか:
ExpressやEJSは聞いたことがある。サンプルアプリのソースを見ると、requireされていたり拡張子だったりする。
Node.jsの本家サイトはこちら: Node.js
この本家サイトをみる前にも、前回の日記で、
$ nvm ls-remote
を実行した時から気にはなっていたのだが、やはりNode.jsの最新バージョンは v4.2.1 らしい。
Node.js と NPM の最新バージョンを導入し直した
Mac OS X 用のインストーラ(pkg)をダウンロードし、インストール実行したら1分程度で完了。インストール場所は次の通り:
- Node.js: /usr/local/bin/node
- NPM: /usr/local/bin/npm
インストーラによると /usr/local/bin/ が $PATH に追加されていることを確認しろとのこと。大丈夫。
ちなみに、npmは別ファイルへのシンボリックリンクになっており、実体はどうやらJavaScriptらしい。バージョンを確認:
$ node -v
v4.2.1
$ npm -v
2.14.7
よし。
不要になった Node.js など
~/work.nvm/* や ~/.bash_profile に追記した source 文などは破棄。
オススメのパッケージをどんどん入れちゃう
参考:
まずは socket.io , express , ejs から。
$ npm install socket.io
> bufferutil@1.2.1 install ./node_modules/socket.io/node_modules/engine.io/node_modules/ws/node_modules/bufferutil
> node-gyp rebuild
CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
SOLINK_MODULE(target) Release/bufferutil.node
> utf-8-validate@1.2.1 install ./node_modules/socket.io/node_modules/engine.io/node_modules/ws/node_modules/utf-8-validate
> node-gyp rebuild
CXX(target) Release/obj.target/validation/src/validation.o
SOLINK_MODULE(target) Release/validation.node
> bufferutil@1.2.1 install ./node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws/node_modules/bufferutil
> node-gyp rebuild
CXX(target) Release/obj.target/bufferutil/src/bufferutil.o
SOLINK_MODULE(target) Release/bufferutil.node
> utf-8-validate@1.2.1 install ./node_modules/socket.io/node_modules/socket.io-client/node_modules/engine.io-client/node_modules/ws/node_modules/utf-8-validate
> node-gyp rebuild
CXX(target) Release/obj.target/validation/src/validation.o
SOLINK_MODULE(target) Release/validation.node
socket.io@1.3.7 node_modules/socket.io
├── debug@2.1.0 (ms@0.6.2)
├── has-binary-data@0.1.3 (isarray@0.0.1)
├── socket.io-adapter@0.3.1 (object-keys@1.0.1, debug@1.0.2, socket.io-parser@2.2.2)
├── socket.io-parser@2.2.4 (isarray@0.0.1, debug@0.7.4, component-emitter@1.1.2, benchmark@1.0.0, json3@3.2.6)
├── engine.io@1.5.4 (base64id@0.1.0, debug@1.0.3, engine.io-parser@1.2.2, ws@0.8.0)
└── socket.io-client@1.3.7 (to-array@0.1.3, indexof@0.0.1, object-component@0.0.3, component-bind@1.0.0, debug@0.7.4, backo2@1.0.2, component-emitter@1.1.2, has-binary@0.1.6, parseuri@0.0.2, engine.io-client@1.5.4)
$ npm install express
express@4.13.3 node_modules/express
├── escape-html@1.0.2
├── merge-descriptors@1.0.0
├── array-flatten@1.1.1
├── cookie@0.1.3
├── utils-merge@1.0.0
├── cookie-signature@1.0.6
├── fresh@0.3.0
├── methods@1.1.1
├── range-parser@1.0.2
├── vary@1.0.1
├── path-to-regexp@0.1.7
├── etag@1.7.0
├── content-type@1.0.1
├── parseurl@1.3.0
├── serve-static@1.10.0
├── content-disposition@0.5.0
├── depd@1.0.1
├── qs@4.0.0
├── finalhandler@0.4.0 (unpipe@1.0.0)
├── on-finished@2.3.0 (ee-first@1.1.1)
├── debug@2.2.0 (ms@0.7.1)
├── proxy-addr@1.0.8 (forwarded@0.1.0, ipaddr.js@1.0.1)
├── accepts@1.2.13 (negotiator@0.5.3, mime-types@2.1.7)
├── type-is@1.6.9 (media-typer@0.3.0, mime-types@2.1.7)
└── send@0.13.0 (destroy@1.0.3, statuses@1.2.1, ms@0.7.1, mime@1.3.4, http-errors@1.3.1)
$ npm install ejs
ejs@2.3.4 node_modules/ejs
インストールといっても npm コマンドを実行したカレントディレクトリに ./node_modules ディレクトリを作って、その配下にダウンロードするというものらしい。依存するパッケージも合わせてダウンロードしてくれるらしく、socket.ioとexpressに関しては node_modules/*/node_modules のような構造になっていたりする。
導入した3つのモジュールの概略
socket.io
WebSocketのNode.js実装。
Express
MVCフレームワークで、MVC生成機能、ルーティング機能、モデル機能なるものを提供。
EJS
Node.jsで人気のテンプレートエンジン。
続いて参考記事を読み進める:
$ npm install jsdom
jsdom@7.0.2 node_modules/jsdom
├── acorn-globals@1.0.6
├── webidl-conversions@2.0.0
├── xml-name-validator@2.0.1
├── browser-request@0.3.3
├── abab@1.0.0
├── cssom@0.3.0
├── symbol-tree@3.1.3
├── nwmatcher@1.3.6
├── tough-cookie@2.2.0
├── parse5@1.5.0
├── whatwg-url-compat@0.6.5 (tr46@0.0.2)
├── acorn@2.4.0
├── htmlparser2@3.8.3 (domelementtype@1.3.0, entities@1.0.0, domhandler@2.3.0, readable-stream@1.1.13, domutils@1.5.1)
├── escodegen@1.7.0 (estraverse@1.9.3, esutils@2.0.2, optionator@0.5.0, source-map@0.2.0, esprima@1.2.5)
├── cssstyle@0.2.30
└── request@2.65.0 (aws-sign2@0.6.0, forever-agent@0.6.1, caseless@0.11.0, stringstream@0.0.5, tunnel-agent@0.4.1, oauth-sign@0.8.0, isstream@0.1.2, json-stringify-safe@5.0.1, extend@3.0.0, node-uuid@1.4.3, qs@5.2.0, combined-stream@1.0.5, mime-types@2.1.7, form-data@1.0.0-rc3, http-signature@0.11.0, bl@1.0.0, hawk@3.1.0, har-validator@2.0.2)
$ npm install validator
validator@4.2.1 node_modules/validator
$ npm install oauth
oauth@0.9.14 node_modules/oauth
$ npm install mysql
mysql@2.9.0 node_modules/mysql
├── bignumber.js@2.0.7
└── readable-stream@1.1.13 (isarray@0.0.1, inherits@2.0.1, string_decoder@0.10.31, core-util-is@1.0.1)
導入した4つのモジュールの概略
jsdom
HTMLに対してDOM操作が使えるようになる。
node-validator
バリデーション、文字列操作、サニタイジング。
node-oauth
node-mysql
MySQL接続できるようになる。
気付き
ちなみに、npm install コマンドを実行する際に node-validator とか node-oauth などと入力すると実在するらしく、何やらインストールされるので注意。
間違えてインストールしたら
npm uninstall node-validator node-oauth
とすればよい。
ふと思ったのだが、依存するモジュールはそれぞれがサブディレクトリに保持するのであれば、同じモジュールに依存する場合であってもコピーを重複保持することになるのかな?
リンク集
- Node.jsでアプリを作るコンペのサイト・・・
- WebのトラフィックをWebSocketでリアルタイム分析するサービス・・・
- Webブラウザ上で動くJavaScript用のIDE(その1)・・・
- Webブラウザ上で動くJavaScript用のIDE(その2)・・・
いまは、こういうものが一般に出回っている時代なんですね。。
なお、参考元の記事を読みながら、ローカルで実行しつつ、ノートしてる感じの日記になってしまっていますが、あしからず。m(_ _)m
次のお題候補
- 最小限のアプリケーションに必要な構成要素(構成ファイル、ディレクトリ構造)
- その他
気が向いたら更新するでしょう。
Node.jsの第一歩:インストールしてみた
とあるクラウドの解説記事に出てくるサンプルアプリを作ってみるにあたり、どうやら避けて通れない要素技術らしいので、触ってみることに。Node.jsは大量のリクエストをさばくのに向いているらしく、速いらしい。
さて、どれくらい触ったらよいものだろうか。。。ひとまずお決まりのHelloまでやったのでメモを兼ねて整理してみた。
ローカルに初めてNode.js環境をつくるにあたり参考にしたサイト:
githubからnvmリポジトリをクローンする形でnvmをインストール
$ mkdir work.nvm
$ git clone https://github.com/creationix/nvm.git ~/work.nvm
$ ls work.nvm/
$ source work.nvm/nvm.sh
$ nvm help
Node.jsのバージョン管理ツール nvm を使って Node.js ver.0.12.7 をインストール
$ nvm ls-remote
$ nvm install v0.12.7
$ node -v
$ nvm alias default v0.12.7
nvm 実行環境(大げさか?)をセットアップ
bashのfunctionやら何やらが定義されているスクリプトをログイン時に毎回ロードするようにしておく。
$ vi ~/.bash_profile
$ tail -n 3 ~/.bash_profileif -s ~/work.nvm/nvm.sh ;
then source ~/work.nvm/nvm.sh
fi
動作確認
いわゆる「サーバーサイドでJavaScriptを動かす」というもの。
$ mkdir -p ~/hello-node.js
$ cd ~/hello-node.js/
$ vi example.js
$ cat example.js
$ node example.js &
$ wget http://localhost:8124
$ cat index.html
ここまでくるのにかかった作業ステップが短く、起動が速い。。
ここで少し用語整理
NPMというものがNVMをインストールしたら同梱されている模様。
$ which npm
~/work.nvm/versions/node/v0.12.7/bin/npm
- NPM (Node Package Manager) : Node.js で作られたモジュールを管理するツール
- NVM (Node Version Manager) : Node.js 自体をバージョン管理するツール
以下のサイトに触りかけると登場するので一応あらかじめ。
次にやってみたいこと
・・・一読し、一通り触ってみました。
・・・読んでみましたがよくわかりませんでした。熟読はしていません。