プロセスモデル
最終更新日 2022年01月27日(木)
Unix プロセスモデルは、サーバーサイドプログラムを実行するためのシンプルで強力な抽象化です。このモデルには、Web アプリの負荷を分散したり、時間の経過とともにスケールしたりすることを考える上で役立つ方法があります。Heroku では、Web、Worker、およびほかのすべてのタイプの dyno に Unix プロセスモデルを使用しています。
基本
初めに、有名な Unix のデーモンである memcached を使って、プロセスモデルの基本を簡単に説明します。
まず、ご使用のプラットフォームに該当する手順を使用して、memcahed をダウンロードしてコンパイルします。
次に、プログラムを実行します。
$ ./memcached -vv
...
<17 server listening (auto-negotiate)
<18 send buffer was 9216, now 3728270
この実行中のプログラムをプロセスといいます。
ローカルの開発ではターミナルでプロセスを手動で実行しても構いませんが、本番のデプロイメントでは、アプリのプロセスは管理対象にする必要があります。管理対象プロセスは、オペレーティングシステムの起動時に自動的に実行する必要があり、何らかの理由でシステムが停止した場合は再起動する必要があります。
従来型のサーバーベースのデプロイメントでは、オペレーティングシステムがプロセスマネージャーを提供します。macOS に内蔵のプロセスマネージャーは launchd と呼ばれ、Ubuntu では systemd が内蔵のプロセスマネージャーです。Heroku では、Dyno Manager が類似の方式を提供しています。
プロセスモデルの基礎を理解したので、次にその原則を実行に移す斬新的な方法、つまり Web アプリの実行について説明します。
Web アプリへの Unix プロセスモデルのマッピング
memcached のようなサーバーデーモンには単一のエントリポイントがあります。つまり、起動するために実行するコマンドは 1 つのみです。 一方、Web アプリには、通常、2 つ以上のエントリポイントがあります。 Web アプリの各エントリポイントは、プロセスタイプとも呼ばれます。
基本的な Rails アプリには、通常、Rack 互換の Web プロセスタイプ (Webrick や Unicorn など) とキューイングライブラリを使用する Worker プロセスタイプ (Delayed Job や Resque など) の 2 つのプロセスタイプがあります。 たとえば、次のようになります。
プロセスタイプ | コマンド |
---|---|
Web | bundle exec rails server |
Worker | bundle exec rake jobs:work |
基本的な Django アプリでも同様です。Web プロセスタイプは manage.py
管理ツールで、バックグラウンドジョブは Celery 経由で実行できます。
プロセスタイプ | コマンド |
---|---|
Web | python manage.py runserver |
Worker | celeryd --loglevel=INFO |
Java アプリのプロセスタイプは、次のようになります。
プロセスタイプ | コマンド |
---|---|
Web | java $JAVA_OPTS -jar web/target/dependency/webapp-runner.jar --port $PORT web/target/*.war |
Worker | sh worker/target/bin/worker |
プロセスタイプはアプリごとに異なります。たとえば、一部の Rails アプリでは Delayed Job の代わりに Resque を使用したり、複数のタイプの Worker があることもあります。各 Heroku アプリで、独自のプロセスタイプを宣言します。
Heroku アプリのプロセスタイプは、アプリのルートディレクトリに常駐する Procfile と呼ばれる特別なファイルで宣言します。heroku local
CLI コマンドを使用すると、開発環境の Procfile で定義したコマンドを簡単に実行できます。詳細は、Procfile のドキュメントを参照してください。
プロセスタイプと dyno
スケールアップするためには、プロセスタイプと dyno の関係を十分に理解しておく必要があります。
プロセスタイプは、dyno のインタンス生成元となるプロトタイプです。 これは、オブジェクト指向プログラミングでクラスがオブジェクトのインスタンス生成元となるプロトタイプであるのに似ています。
dyno (縦軸) とプロセスタイプ (横軸) の関係を次の図で示します。
縦軸の dyno はスケールです。 そのプロセスタイプで処理されるタイプの作業の並列性をスケールする必要がある場合は、この方向を増やします。 Heroku では、この操作を scale
コマンドで実行します。
$ heroku ps:scale web=2 worker=4 clock=1
Scaling web processes... done, now running 2
Scaling worker processes... done, now running 4
Scaling clock processes... done, now running 1
横軸のプロセスタイプは負荷の多様性です。 各プロセスタイプは特定のタイプの作業に特化します。
たとえば、2 種類の Worker が存在する一部のアプリでは、1 つを緊急のジョブに、もう 1 つを長期実行ジョブに使用します。 複数の専用 Worker に細分化することで、緊急のジョブの応答性が向上し、処理リソースの使い方を細かく制御することができます。 キューイングシステムを使用して、ジョブを Worker dyno に分散できます。
プロセスのスケジュール
cron
のように、特定の時刻に、または特定の間隔で作業スケジュールを設定するには、Heroku Scheduler アドオンのようなツールを使用するか、専用のジョブスケジューリングプロセスタイプを使用します。
One-off 管理 dyno
heroku ps:scale
で Dyno Manager によって実行される一連の dyno は、Dyno formation と呼ばれます (たとえば、web=2 worker=4 clock=1)。 継続的に実行される上記の dyno に加え、このプロセスモデルでは、One-off dyno でデータベースの移行やコンソールセッションなどの管理タスクに対応することもできます。
One-off dyno についての詳細を参照してください。
ログとしての出力ストリーム
このプロセスモデルでは、dyno で実行しているすべてのコードのログを STDOUT
に送信する必要があります。 ローカルでは、プロセスからの出力ストリームはターミナルに表示されます。 Heroku では、すべての dyno で実行しているプロセスからの出力ストリームは、heroku logs
コマンドで簡単に表示できるように、 Logplex でまとめて収集されます。