メインコンテンツまでスキップ

HTTPサーバー

HttpServerは、HTTP リクエストの処理を担当する。

HttpServerはパラメータとしてアプリケーションファクトリを受け取り、アプリケーションファクトリはSend + Syncのトレイト境界を持つ必要があります。これについてはマルチスレッドのセクションで詳しく説明します。

Webサーバーを起動するには、まずネットワーク・ソケットにバインドする必要があります。HttpServer::bind()に、ソケットアドレスのタプルまたは文字列("127.0.0.1", 8080)"0.0.0:8080"などの値を指定して実行します。ソケットが他のアプリケーションによって使用されている場合、これは失敗します。

バインドに成功したら、HttpServer::run()を使用してServerのインスタンスを返します。Serverは、リクエストの処理を開始するために待機(await)あるいは起動(spawn)させる必要があり、 シャットダウン信号を受け取るまで実行されます。(デフォルトでは ctrl-c など。詳細はこちら


マルチスレッド

HttpServerは自動的にいくつかの HTTP ワーカーを起動します。デフォルトでは、この数はシステムの物理 CPU の数に等しくなっています。この数はHttpServer::workers()メソッドでオーバーライドすることができます。


Worker が作成されると、それぞれ個別の application インスタンスを受け取り、リクエストを処理します。アプリケーションのステートはスレッド間で共有されず、ハンドラがステートのコピーを自由に操作するので、同時に実行される心配はありません。

アプリケーションのステートは SendSync である必要はありませんが、アプリケーションファクトリは Send + Sync でなければなりません。

Worker スレッド間でステートを共有するには、Arc/Data を使用します。共有と同期が導入されたら、特別な注意を払う必要があります。多くの場合、修正のために共有ステート(shared state)をロックした結果、思わぬパフォーマンスコストが発生します。

例えば、非排他的ロックを実現するために mutexes の代わりに read/write locks を使用するなど、より効率的なロック戦略によってこれらのコストを軽減できる場合もありますが、最もパフォーマンスの高い実装は、ロックが全く発生しないものになることが多いようです。

各ワーカスレッドはリクエストを順番に処理するので、現在のスレッドをブロックするハンドラは、現在のワーカーが新規リクエストを処理する事を止めさせることになります。

fn my_handler() -> impl Responder {
std::thread::sleep(Duration::from_secs(5)); // <-- ワーカスレッドが機能停止する原因になります
"response"
}

このため、I/O やデータベース操作など、CPUに縛られない長い操作は、futuresや非同期関数として表現する必要があります。非同期ハンドラはワーカスレッドによって同時に実行されるため、実行をブロックすることはありません。

async fn my_handler() -> impl Responder {
tokio::time::sleep(Duration::from_secs(5)).await; // <-- ワーカースレッドは他のリクエストをここで処理します
"response"
}

同じ制限がエクストラクタにも適用されます。ハンドラ関数がFromRequestを実装した引数を受け取り、その実装が現在のスレッドをブロックする場合、ワーカスレッドはハンドラを実行する際にブロックされます。このため、エクストラクタを実装する際には特に注意が必要で、必要な場合は非同期で実装する必要があります。

TLS / HTTPS

Actix Webは、rustlsOpenslという2つのTLS実装を標準でサポートしています。

rustlsのクレート機能はrustlsとの統合のため、opensslopensslとの統合のためにあります。

[dependencies]
actix-web = { version = "4", features = ["openssl"] }
openssl = { version = "0.10" }

key.pemとcert.pemを作成するには、次のコマンドを使用します。

※証明書のユーザー部分(-subj以下)は、適宜書き換えて下さい

$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days 365 -sha256 -subj "/C=CN/ST=Fujian/L=Xiamen/O=TVlinux/OU=Org/CN=muro.lxd"

パスワードを削除する場合は、nopass.pem を key.pem にコピーしてください。

$ openssl rsa -in key.pem -out nopass.pem

キープアライブ(Keep-Alive)

Actix Webは、後続のリクエストを待つためにコネクションを開いたままにします。

keep alive 接続の動作は、サーバーの設定によって定義されます。

  • Duration::from_secs(75) または KeepAlive::Timeout(75):75秒間のキープアライブタイマーを有効にします。
  • KeepAlive::Os: OSのkeep-aliveを使用します。
  • None or KeepAlive::Disabled: keep-aliveを無効にします。

上記の最初のオプションが選択された場合、HTTP/1.1 リクエストでは、レスポンスが connection typeCloseUpgrade に設定するなどして明示的に拒否していなければ、 keep-alive が有効になります。接続を強制的に閉じるには、HttpResponseBuilderforce_close()メソッドを使用します。

Keep-aliveはHTTP/1.0ではoff、HTTP/1.1とHTTP/2.0ではonになります。


グレースフルシャットダウン

HttpServerはグレースフル・シャットダウン(Graceful Shutdown)をサポートしています。停止シグナルを受け取った後、ワーカーにはリクエストの処理を終えるまでに 決められた時間があります。タイムアウト後にまだ生存しているワーカーは強制的にシャットダウンされます。デフォルトでは、シャットダウンのタイムアウトは 30 秒に設定されています。このパラメータは HttpServer::shutdown_timeout() メソッドで変更することができます。

HttpServerは、いくつかのOSシグナルを処理します。CTRL-C はすべてのOSで利用可能で、その他のシグナルは unix システムで利用可能です。

  • SIGINT - ワーカーを強制終了
  • SIGTERM - ワーカーをグレースフルシャットダウン
  • SIGQUIT - ワーカーを強制終了

HttpServer::disable_signals()メソッドにより、シグナル処理を無効化するも可能です。