2011年5月18日水曜日

Antiwebの設計 - プロセス

パフォーマンスとセキュリティのために、Antiwebは一群のunixプロセスである。本稿は異なるプロセスの役割と責任を述べる。

下図はプロセスと実行中のAntiwebシステムの責任を図示したものである。



ハブ(Hub)プロセス

ハブプロセスは通常、Antiwebシステムにおいてもっとも忙しいプロセスである。その責務は以下のとおり。

  • unixソケットを通じて新しい接続を受け付ける。その接続はワーカープロセスにつなげられるか、あるいはスーパーバイザ接続につなげられるかする。
  • インターネットからHTTP接続を受け付ける。リクエストされた仮想ホスト(vhost)に基づいて接続を適用すべきワーカーを決定し、接続から読み込んだデータをunixソケット越しにワーカーに流す。このプロセスで、ハブプロセス中のソケットを閉じるので、そのソケットはワーカーにおいてのみ開かれていることになる。
  • ワーカープロセスからのすべてのログメッセージを受け取り、それをロガープロセスに転送する。
  • プロセス間メッセージをルーティングする(たとえばスーパーバイザ接続)。

他にハブについて注記すること:

  • ハブプロセスは、ハブ設定ファイルにおいて指定されたユーザないしUIDにおいて動作する。
  • そのプロセスが権限を持たない空ディレクトリに対してchroot()される。
(訳注:Antiwebがどれほどセキュリティを意識しているかを述べている。)

ロガー(Logger)プロセス

ロガープロセスはハブプロセスとunixソケットで接続している。その唯一の仕事はハブプロセスからログメッセージを受け取って、それらをディスクに書き込むことである。ワーカーがログプロセスを作ると、それがハブを通じてロガープロセスにルーティングされる。

  • ハブ設定ファイルにおいて指定されたユーザないしUIDにおいて動作する。
  • 書き込み権限を持つaw_logディレクトリにchroot()される。
  • ロガープロセスはログファイルをchmod()するので、ログファイルは全体に読み書き可となることはけっしてない。

ワーカー(Worker)プロセス

ワーカープロセスはHTTPリクエスト処理の重量挙げを行なう。

  • worker confに指定されたユーザないしUIDにおいて動作する。
  • オプションとして chroot()される。
  • クライアントソケットと接続して転送されるので、ワーカープロセスは後続のHTTPリクエストをこれらのソケットにおいて処理する。それらはハブを経由しない。

Antiweb Tip
なぜ複数のワーカーを動作させたいか?

  • 権限を分けたvhosts
  • SMP/マルチコア
  • ディスクレイテンシの縮小
起動時、各ワーカープロセスはその設定ファイルを読み、HTTPリクエストをディスパッチするための関数をコンパイルする。この関数は与えられたマウントポイントとその他の存在する機能を処理する。起動後、ワーカープロセスはこの設定ファイルを二度と開かない。新しい設定ファイルを提供する唯一の方法は、スーパーバイザプロセスを使ってメッセージを送ることである。これは設定ファイルを含まないルートにワーカーをchroot()させるために不可欠のことだ。
ハブによってそのワーカープロセスが関心を持つべきvhostsを登録すると、そのワーカープロセスはハブ接続を「ロック」して追加のvhostsを登録できないようにする。vhostsを後で追加するには、その接続は手動でスーパーバイザプロセスからアンロックしなければならない(これは、ワーカー設定を-reloadするときに舞台裏で起きることだ --- これと関係する unlikely attack の可能性を見よ)。正しくないワーカー設定を-reloadさせようとすると、Antiwebは新しい設定をインストールせず、もとの設定を使い続ける。ワーカー設定を-reloadしてそれが正しくコンパイルされたが、HTTPリクエストの処理中に何かエラーが生じた場合、Antiwebはワーカーを殺してその理由をsyslogに記録する。

権限の分割
  • ワーカープロセスが自身に属していないvhostsの接続を盗むことはできない。
  • ワーカープロセスが他のワーカーによって作られたログメッセージをインターセプトすることはできない。

Antiwebの設計 - メモリ管理

Antiwebにおいてもっとも重要なメモリ管理システムはlispのガベージコレクタである。AntiwebをサポートするCommon Lispの実装の多くは、すばらしいガベージコレクタを持っているので、負荷の高いベンチマーク以外ではけっして止まっているように見えることはないはずである。

lispの外側では、Antiwebは2つの重要なデータ構造 conns および ioblocks を持つ。これらのデータ構造はファイルsrc/libantiweb.hに定義されている。 拡張子と関係なく、これはCのヘッダファイルではない。lispとCコンパイラの双方でパースできる特殊な書式である。

Antiwebプロセスによって使われているメモリのを-roomコマンドでブレークダウンすることができる。CMUCLを使ってワーカを探索する様子を以下に示す。

# antiweb -room /var/aw/example.conf

"---ANTIWEB MEMORY STATS---
Dynamic Space Usage: 1,946,272 bytes (out of 512 MB).
Read-Only Space Usage: 24,024,304 bytes (out of 256 MB).
Static Space Usage: 3,665,792 bytes (out of 256 MB).
Control Stack Usage: 1,636 bytes (out of 128 MB).
Binding Stack Usage: 88 bytes (out of 128 MB).
The current dynamic space is 0.
Garbage collection is currently enabled.

conns and ioblocks:
Allocated conns: 2, 470 bytes
Allocated ioblocks: 1, 4112 bytes, 14 in use, 99.7% overhead
Free conns: 2, 470 bytes
Free ioblocks: 514, 2113568 bytes
Total: 2118620 bytes + malloc overhead
---END OF ANTIWEB MEMORY STATS---"

ファイル src/libantiweb.c を読んでみると、Antiwebがconn構造体とioblock構造体をmalloc()しながら、それらをけっしてfree()しないことに気づくであろう。Antiwebは、その構造体を使い終わったら、それをフリーリストにプッシュする。次に必要になったときは、直近にフリーリストにプッシュしたものをポップする。connおよびioblock構造体は常に同一の大きさであるので、これがAntiwebに可能なのである。

メモリの解放は危険とみなす

上記の -room の出力において、connおよびioblockの数値は高水位に表示されている。トラフィックが重いとき、より多くのメモリが割り当てられる。トラフィックが落ち着くと、フリーリストの底の方は必要に応じてカーネルによってスワップアウトされる。

Mozilla Firefox ブラウザ無料ダウンロード