LoginSignup
3
4

More than 5 years have passed since last update.

SocketIO を使ったサーバーを複数のプロセスで起動させる

Posted at

SocketIO で HTTP Long Polling を使う場合、ひとつのコネクションが複数のプロセスにまたがることを許容しない

Node の cluster モジュールsticky-session を使うと同じ IP アドレスからの接続を固定のサーバープロセスでクライアントからの要求を処理できる (スティッキーセッション)。だが PM2 の cluster モードは sticky-session に対応していない。そのため、SocketIO を使っている場合は PM2 の cluster モードが使えない。

cluster モードを使わないとひとつのプロセスですべての処理をさせることになり、サーバー資源を余らせてしまう。なのでどうにかして対処したい。

fork モードを使う

PM2 の fork モードを使うと複数のプロセスを起動させられる。

PM2 は fork モードでプロセスを起動させると環境変数「NODE_APP_INSTANCE」(process.env.NODE_APP_INSTANCE) にインスタンス ID を入れる。インスタンス ID は 0 からプロセスの数に応じて増える。そのため、基準となるポート番号に環境変数「NODE_APP_INSTANCE」の値を加えることにより、複数のポート番号でサーバープロセスを起動できる。

server.js
// ...

var app = express();
var server = http.createServer(app);
var io = socketIO(server);

// ...

var port = 8080 + Number(process.env.NODE_APP_INSTANCE || 0);
server.listen(port);

H2O からリバースプロキシする

H2OProxy Directives は同一ホスト名で異なるポート番号のサーバーにリバースプロキシできない。

そのため、Nginx を介さなければならない。

Nginx の upstream ディレクティブに羅列させ、ip_hash ディレクティブを使うと cluster モジュールと sticky-session を使ったときと同様に同じ IP アドレスからの接続を固定のサーバープロセスで処理させられる。

/etc/nginx/conf.d/example-app.conf
upstream example-app {
  ip_hash;
  server 127.0.0.1:8080;
  server 127.0.0.1:8081;
  server 127.0.0.1:8082;
  server 127.0.0.1:8083;
}

server {
  listen 10000;

  location / {
    proxy_pass http://example-app;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

あとは Nginx に対して H2O からリバースプロキシするだけで良い。

/etc/h2o/h2o.conf
hosts:
  "example.com:443":
    listen:
      port: 443
      ssl:
        certificate-file: /etc/letsencrypt/live/example.com/fullchain.pem
        key-file: /etc/letsencrypt/live/example.com/privkey.pem
    paths:
      /:
        proxy.reverse.url: http://127.0.0.1:10000/
        proxy.timeout.io: 10000
        proxy.websocket: ON

構成図

                                      +-------------------+
                                      |                   |
                                      | Redis (port 6379) |
                                      |                   |
                                      +---------+---------+
                                                |
          +------------------------+------------+-----------+------------------------+
          |                        |                        |                        |
+---------+---------+    +---------+---------+    +---------+---------+    +---------+---------+
|                   |    |                   |    |                   |    |                   |
| Node (port 8080)  |    | Node (port 8081)  |    | Node (port 8082)  |    | Node (port 8083)  |
|                   |    |                   |    |                   |    |                   |
+---------+---------+    +---------+---------+    +---------+---------+    +---------+---------+
          |                        |                        |                        |
          +------------------------+------------+-----------+------------------------+
                                                |
                                      +---------+---------+
                                      |                   |
                                      | Nginx (port 10000)|
                                      |                   |
                                      +---------+---------+
                                                |
                                      +---------+---------+
                                      |                   |
                                      |   H2O (port 443)  |
                                      |                   |
                                      +-------------------+

わたしは HTTP/2 でサーバープッシュが使いたかったのと、brotil を使いたかったため H2O にポート 443 番を返してもらっている。

ALPN に対応している OpenSSL 1.0.2 以降で Nginx をビルドできる環境で、かつサーバープッシュが不要であるのならば、H2O ではなく Nginx にポート 443 番を返してもらえば良いだろう。そのほうが構成もシンプルになり、管理の手間も減る。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4