Skip to content

Instantly share code, notes, and snippets.

@meso
Last active September 26, 2024 07:32
Show Gist options
  • Save meso/6805914 to your computer and use it in GitHub Desktop.
Save meso/6805914 to your computer and use it in GitHub Desktop.

Node.js 入門

  • 清水俊博(@meso)
    • 株式会社ドワンゴ 技術コミュニケーション室
    • Node.js 日本ユーザグループ

Node.js とは何か

  • Webブラウザ外で動作する、ノンブロッキングI/O環境上に構築されたJavaScriptの実行環境(プラットフォーム)

  • いわゆる"サーバサイドJavaScript"の1つ

サーバサイドJavaScript

  • Node.js 以外にも従来からいくつも存在

    • Netscape Enterprise Server, IIS+JScript, Helma
    • Aptana Jaxer, Narwhal, RingoJS
  • 流行らなかった

    • JavaScriptがしっかりしたプログラミング言語として認められてなかった時代
    • 「別にサーバサイドまでJavaScript使いたいと思わないんだけど」で玉砕
  • Node.jsの目的は「サーバサイドでJavaScriptを使いたい」ではない

Node.jsの目的

  • Node.jsの作者Ryan Dahlの目指したもの

    • Node's goal is to provide an easy way to build scalable network programs.
    • Nodeの目的は、スケーラブルなネットワークプログラムを作成する簡単な方法を提供することです
  • この目的を達成するには、解決しなければいけない問題があった

解決しなければいけない問題

  • C10K問題
    • ハードウェアの性能に関わらず、同時接続できるクライアント数に限界がきてしまう問題
      • リアルタイムWebの普及で現実になってきた
    • 原因は複合的だが、主な原因の1つはスレッド数の増大
      • メモリ割り当て
        • 1スレッド増えるとOSにより2~4M割り当てられる
      • コンテキストスイッチ
        • スレッドが増えると、処理を走らせるスレッドを切り替えるのにもコストがかかる

従来のWebサーバ

  • スレッドモデル

  • 1リクエストに対して1スレッド

    • レスポンスを返すとスレッドは終了
  • たとえ分間1万アクセスだとしても、スレッドが同時に1万本必要にはなるようなことはない

    • レスポンスを返すのに1分かかるような特殊なWebアプリケーションでもない限り

スレッドモデル

Software Design 2011年9月号

リアルタイムWebが使う技術

  • Comet

    • サーバがレスポンスをすぐに返さずに保持し、必要なデータが用意できたら返す仕組み
  • WebSocket

    • サーバとブラウザ間でSocketを張りっぱなしにして、いつでも通信ができる
  • これらによって、分間1万アクセスならスレッドが同時に1万本必要になってしまう

どうやって解決したか

  • イベントループモデル

  • ノンブロッキングI/O

イベントループモデル

  • 1つのスレッドがイベントの発生を待機

  • イベントが発生したらそのイベントに即した処理を行う

  • 重い処理を行う際には「その処理が終わったというイベントが発生したら行う処理」を登録し、次のイベントの発生を待つ

    • 重い処理の結果が返ってくるのをその場で待ち続けはしない
  • シングルスレッドでも多数の同時リクエストをさばくことが出来る

イベントループモデルの図

Software Design 2011年9月号

リクエスト数の比較

http://blog.webfaction.com/2008/12/a-little-holiday-present-10000-reqssec-with-nginx-2/

メモリ使用量の比較

http://blog.webfaction.com/2008/12/a-little-holiday-present-10000-reqssec-with-nginx-2/

イベントループモデルの問題点

  • 1箇所でも重い処理を持つコードがあれば、シングルスレッドゆえに全体の性能が低下する

  • プログラムにとっての重い処理

    = CPUがフルに働けずに待ち時間が発生する処理

    = ディスクやネットワークのI/O待ち

I/Oの待ちのコスト

種別 サイクル メートル換算
L1キャッシュ 3 3m
L2キャッシュ 14 14m
メモリ 250 250m
ディスク 41,000,000 地球1週
ネットワーク 240,000,000 地球6週

ノンブロッキングI/O

  • プログラマが見極めるんじゃなくて、強制的にI/Oを非同期にしてしまおう
  • libuv(libev, libeio)によって実現
  • I/O待ちによってブロックされることがないため性能が低下しない

コード例

  • ブロッキングI/O

var user = db.exec('select * from users where id=123'); // 結果をここで待つ display(user.name); ```

  • ノンブロッキングI/O

db.exec('select * from users where id=123', function(user) { // 結果を受け取ったらここが呼ばれる display(user.name); }); // 結果を待たずにここにくる ```

Because nothing blocks, less-than-expert programmers are able to develop fast systems.

  • このようなプラットフォームをどの言語向けに提供すべきか

JavaScript

  • シングルスレッドモデルである

  • イベントループの仕組みが備わっている

  • 標準入出力の仕様がない

    = 既存のI/Oライブラリが存在しない

    = 全てのI/Oがノンブロッキングな世界を0から作り上げられる環境

  • cf. Twisted, AnyEvent, EventMachine

JavaScriptによる恩恵

  • ブラウザ戦争のおかげで高速なV8エンジン
  • ユーザベースが大きい
  • 新たな言語を覚えなくてよい
  • 開発環境やツールが整備されている

適した利用分野

  • リアルタイムWebアプリケーション, ネットワーク・サーバ
    • チャット, ゲーム, コラボレーションツール, Streaming, etc...
  • クローラー
    • 大量のI/Oウエイトが発生するがその時間を無駄にしない
    • jQueryなどのDOM操作系のJSライブラリが使えるのでスクレイピングが楽ちん

HTTPサーバ

var http = require('http');

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

console.log('Server running at http://127.0.0.1:1337/');

TCPエコーサーバ

var net = require('net');

var server = net.createServer(function (socket) {
  socket.write('Echo server\r\n');
  socket.pipe(socket);
});

server.listen(1337, '127.0.0.1');

活用事例

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment