プロダクション環境へのデプロイ

Xitrumを直接動かすことができます:

ブラウザ ------ Xitrum インスタンス

HAProxyのようなロードバランサーや、ApacheやNginxのようなリバースプロキシの背後で動かすこともできます:

ブラウザ ------ ロードバランサー/リバースプロキシ   -+---- Xitrum インスタンス1
                                             +---- Xitrum インスタンス2

ディレクトリのパッケージ化

sbt/sbt xitrum-package を実行することで、プロダクション環境へデプロイ可能な target/xitrum ディレクトリが生成されます:

target/xitrum
  config
    [config files]
  public
    [static public files]
  lib
    [dependencies and packaged project file]
  script
    runner
    runner.bat
    scalive
    scalive.jar
    scalive.bat

xitrum-packageのカスタマイズ

デフォルトでは sbt/sbt xitrum-package コマンドは、

configpublic および script ディレクトリを target/xitrum 以下にコピーします。 コピーするディレクトリを追加したい場合は、以下のように build.sbt を編集します:

XitrumPackage.copy("config", "public, "script", "doc/README.txt", "etc.")

詳しくは xitrum-packageのサイト を参照ください。

稼働中のJVMプロセスに対するScalaコンソール接続

プロダクション環境においても特別な準備をすることなく、Scalive を使用することで、 稼働中のJVMプロセスに対してScalaコンソールを接続してデバッギングを行うことができます。

script ディレクトリの scalive コマンドを実行します:

script
  runner
  runner.bat
  scalive
  scalive.jar
  scalive.bat

CentOSまたはUbuntuへのOracleJDKインストール

ここではJavaのインストール方法についての簡単なガイドを紹介します。 パッケージマネージャを使用してJavaをインストールすることも可能です。

現在インストールされているJavaの確認:

sudo update-alternatives --list java

出力例:

/usr/lib/jvm/jdk1.7.0_15/bin/java
/usr/lib/jvm/jdk1.7.0_25/bin/java

サーバ環境の確認 (32 bit または 64 bit):

file /sbin/init

出力例:

/sbin/init: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x4efe732752ed9f8cc491de1c8a271eb7f4144a5c, stripped

JDKを Oracle のサイトからダウンロードします。 ブラウザを介さないでダウンロードするにはちょっとした 工夫 が必要です:

wget --no-cookies --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com" "http://download.oracle.com/otn-pub/java/jdk/7u45-b18/jdk-7u45-linux-x64.tar.gz"

ダウンロードしたアーカイブを解凍して移動します:

tar -xzvf jdk-7u45-linux-x64.tar.gz
sudo mv jdk1.7.0_45 /usr/lib/jvm/jdk1.7.0_45

コマンドを登録します:

sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.7.0_45/bin/java" 1
sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.7.0_45/bin/javac" 1
sudo update-alternatives --install "/usr/bin/javap" "javap" "/usr/lib/jvm/jdk1.7.0_45/bin/javap" 1
sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.7.0_45/bin/javaws" 1

対話型のシェルで新しいパスを指定します:

sudo update-alternatives --config java

出力例:

There are 3 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                               Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/jdk1.7.0_25/bin/java   50001     auto mode
  1            /usr/lib/jvm/jdk1.7.0_15/bin/java   50000     manual mode
  2            /usr/lib/jvm/jdk1.7.0_25/bin/java   50001     manual mode
  3            /usr/lib/jvm/jdk1.7.0_45/bin/java   1         manual mode

Press enter to keep the current choice[*], or type selection number: 3
update-alternatives: using /usr/lib/jvm/jdk1.7.0_45/bin/java to provide /usr/bin/java (java) in manual mode

バージョンを確認します:

java -version

出力例:

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

javac等も同様に行います:

sudo update-alternatives --config javac
sudo update-alternatives --config javap
sudo update-alternatives --config javaws

システム起動時にXitrumをスタートさせる

script/runner*nix環境向け)と script/runner.bat (Windows環境向け)はオブジェクトの main メソッドを実行するためのスクリプトになります。 プロダクション環境ではこのスクリプトを使用してWebサーバを起動します:

script/runner quickstart.Boot

JVM設定 を調整するには、 runner (または runner.bat)を修正します。 また、config/xitrum.conf も参照してください。

Linux環境でシステム起動時にXitrumをバックグラウンドでスタートさせるには、一番簡単な方法は /etc/rc.local に一行を追加します:

su - user_foo_bar -c /path/to/the/runner/script/above &

他には daemontools が便利です。 CentOSへのインストール手順は こちらの手順 を参照してください。 あるいは Supervisord を使用することもできます。

/etc/supervisord.conf の例:

[program:my_app]
directory=/path/to/my_app
command=/path/to/my_app/script/runner quickstart.Boot
autostart=true
autorestart=true
startsecs=3
user=my_user
redirect_stderr=true
stdout_logfile=/path/to/my_app/log/stdout.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=7
stdout_capture_maxbytes=1MB
stdout_events_enabled=false
environment=PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:~/bin

その他のツール:

ポートフォワーディングの設定

デフォルトではXitrumは8000ポートと4430ポートを使用します。 これらのポート番号は config/xitrum.conf で設定することができます。

/etc/sysconfig/iptables を以下のコマンドで修正することによって、 80から8000へ、443から4430へポートフォワーディングを行うことができます:

sudo su - root
chmod 700 /etc/sysconfig/iptables
iptables-restore < /etc/sysconfig/iptables
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8000
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 4430
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8000
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 443 -j REDIRECT --to-ports 4430
iptables-save -c > /etc/sysconfig/iptables
chmod 644 /etc/sysconfig/iptables

もしApacheが80ポート、443ポートを使用している場合、停止する必要があります:

sudo /etc/init.d/httpd stop
sudo chkconfig httpd off

Iptablesについての参考情報:

大量コネクションに対するLinux設定

Macの場合、JDKは IO (NIO) に関わるパフォーマンスの問題 が存在します。

参考情報(英語):

ファイルディスクリプタ数の上限設定

各コネクションはLinuxにとってオープンファイルとしてみなされます。 1プロセスが同時オープン可能なファイルディスクリプタ数は、デフォルトで1024となっています。 この上限を変更するには /etc/security/limits.conf を編集します:

*  soft  nofile  1024000
*  hard  nofile  1024000

変更を適用するには一度ログアウトして、再度ログインする必要があります。 一時的に適用するには ulimit -n と実行します。

カーネルのチューニング

A Million-user Comet Application with Mochiweb(英語) に紹介されているように、/etc/sysctl.conf を編集します:

# General gigabit tuning
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# This gives the kernel more memory for TCP
# which you need with many (100k+) open socket connections
net.ipv4.tcp_mem = 50576 64768 98152

# Backlog
net.core.netdev_max_backlog = 2048
net.core.somaxconn = 1024
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_syncookies = 1

# If you run clients
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 10

変更を適用するため、 sudo sysctl -p を実行します。 リブートの必要はありません。これでカーネルは大量のコネクションを扱うことができるようになります。

バックログについて

TCPはコネクション確立のために3種類のハンドシェイクを行います。 リモートクライアントがサーバに接続するとき、クライアントはSYNパケットを送信します。 そしてサーバ側のOSはSYN-ACKパケットを返信します。 その後リモートクライアントは再びACKパケットを送信してコネクションが確立します。 Xitrumはコネクションが完全に確立した時にそれを取得します。

Socket backlog tuning for Apache(英語) によると、 コネクションタイムアウトは、WebサーバのバックログキューがSYN−ACKパケット送信で溢れてしまった際に、SYNパケットが失われることによって発生します。

FreeBSD Handbook(英語) によると デフォルトの128という設定は、高負荷なサーバ環境にとって、新しいコネクションを確実に受け付けるには低すぎるとあります。 そのような環境では、1024以上に設定することが推奨されています。 キューサイズを大きくすることはDoS攻撃を避ける意味でも効果があります。

Xitrumはバックログサイズを1024(memcachedと同じ値)としています。 しかし、前述のカーネルのチューニングをすることも忘れないで下さい。

バックログ設定値の確認方法:

cat /proc/sys/net/core/somaxconn

または:

sysctl net.core.somaxconn

一時的な変更方法:

sudo sysctl -w net.core.somaxconn=1024

HAProxy tips

HAProxyをSockJSのために設定するには、こちらのサンプル を参照してください。

defaults
    mode http
    timeout connect 10s
    timeout client  10h  # Set to long time to avoid WebSocket connections being closed when there's no network activity
    timeout server  10h  # Set to long time to avoid ERR_INCOMPLETE_CHUNKED_ENCODING on Chrome

frontend xitrum_with_discourse
    bind 0.0.0.0:80

    option forwardfor

    acl is_discourse path_beg /forum
    use_backend discourse if is_discourse
    default_backend xitrum

backend xitrum
    server srv_xitrum 127.0.0.1:8000

backend discourse
    server srv_discourse 127.0.0.1:3000

HAProxyを再起動せずに設定ファイルをロードするには、こちらのディスカッション を参照してください。

HAProxyはNginxより簡単に使うことができます。 キャッシュについての章 にあるように、Xitrumは 静的ファイルの配信に優れている ため、 静的ファイルの配信にNginxを用意する必要はありません。その点からHAProxyはXitrumととても相性が良いと言えます。

Nginx tips

Nginx 1.2 の背後でXitrumを動かす場合、XitrumのWebSocketやSockJSの機能を使用するには、 nginx_tcp_proxy_module を使用する必要があります。 Nginx 1.3+ 以上はネイティブでWebSocketをサポートしています。

Nginxはデフォルトでは、HTTP 1.0をリバースプロキシのプロトコルとして使用します。 チャンクレスポンスを使用する場合、Nginxに HTTP 1.1をプロトコルとして使用することを伝える必要があります:

location / {
  proxy_http_version 1.1;
  proxy_set_header Connection "";
  proxy_pass http://127.0.0.1:8000;
}

http keepaliveについての ドキュメント にあるように、 proxy_set_header Connection "" と設定する必要もあります。

Herokuへのデプロイ

Xitrumは Heroku 上で動かすこともできます。

サインアップとリポジトリの作成

公式ドキュメント に沿って、サインアップしリポジトリを作成します。

Procfileの作成

Procfileを作成し、プロジェクトのルートディレクトリに保存します。 Herokuはこのファイルをもとに、起動時コマンドを実行します。

web: target/xitrum/script/runner <YOUR_PACKAGE.YOUR_MAIN_CLASS>

Port設定の変更

ポート番号はHerokuによって動的にアサインされるため、以下のように設定する必要があります。

config/xitrum.conf:

port {
  http              = ${PORT}
  # https             = 4430
  # flashSocketPolicy = 8430  # flash_socket_policy.xml will be returned
}

SSLを使用するには、アドオン が必要となります。

ログレベルの設定

config/logback.xml:

<root level="INFO">
  <appender-ref ref="CONSOLE"/>
</root>

Herokuで稼働するアプリのログをtailするには:

heroku logs -tail

xitrum-package のエイリアス作成

デプロイ実行時にHerokuは、sbt/sbt clean compile stage を実行します。 そのため、 xitrum-package に対するエイリアスを作成する必要があります。

build.sbt:

addCommandAlias("stage", ";xitrum-package")

Herokuへのプッシュ

デプロイプロセスは git push にふっくされます:

git push heroku master

詳しくはHerokuの 公式ドキュメント for Scala を参照してください.

OpenShiftへのデプロイ

Xitrumは OpenShift 上で動かすこともできます。

サインアップとリポジトリの作成

公式ガイド に沿って、サインアップしリポジトリを作成します。 カートリッジには DIY を指定します。

rhc app create myapp diy

プロジェクト構成

sbtを使用してXitrumアプリケーションをコンパイル、起動するために、いくつかの準備 が必要となります。 rhcコマンドで作成したプロジェクトディレクトリ内に`app`ディレクトリを作成し、xitrumアプリケーションのソースコードを配置します。 また、空の`static`と`fakehome`ディレクトリを作成します、 プロジェクトツリーは以下のようになります。

├── .openshift
│   ├── README.md
│   ├── action_hooks
│   │   ├── README.md
│   │   ├── start
│   │   └── stop
│   ├── cron
│   └── markers
├── README.md
├── app
├── fakehome
├── misc
└── static

action_hooksの作成

openshiftへpush時に実行されるスクリプトを以下のように修正します。

.openshift/action_hooks/start:

#!/bin/bash
IVY_DIR=$OPENSHIFT_DATA_DIR/.ivy2
mkdir -p $IVY_DIR
chown $OPENSHIFT_GEAR_UUID.$OPENSHIFT_GEAR_UUID -R "$IVY_DIR"
cd $OPENSHIFT_REPO_DIR/app
sbt/sbt xitrum-package
nohup $OPENSHIFT_REPO_DIR/app/target/xitrum/script/runner quickstart.Boot >> nohup.out 2>&1 & echo $! > $OPENSHIFT_REPO_DIR/xitrum.pid &

.openshift/action_hooks/top:

#!/bin/bash
source $OPENSHIFT_CARTRIDGE_SDK_BASH

# The logic to stop your application should be put in this script.
if [ -z "$(ps -ef | grep `cat $OPENSHIFT_REPO_DIR/xitrum.pid` | grep -v grep)" ]
then
    client_result "Application is already stopped"
else
    cat $OPENSHIFT_REPO_DIR/xitrum.pid | xargs kill
fi

IP:Port設定の変更

IPとポート番号はopenshiftによって動的にアサインされるため、以下のように設定する必要があります。

config/xitrum.conf:

# Use opensift's Environment Variables
interface = ${OPENSHIFT_DIY_IP}

# Comment out the one you don't want to start.
port {
  http  = ${OPENSHIFT_DIY_PORT}

sbt引数の修正

opensift上でsbtが動かすために、sbt起動スクリプトに以下のオプションを追加します。

sbt/sbt:

-Duser.home=$OPENSHIFT_REPO_DIR/fakehome -Dsbt.ivy.home=$OPENSHIFT_DATA_DIR/.ivy2 -Divy.home=$OPENSHIFT_DATA_DIR/.ivy2

openshiftへのpush

アプリケーションを起動するにはopensiftへソースコードをプッシュします。

git push