# 2. HAProxy のアーキテクチャ

> プロセス、スレッド、イベントループ、chroot、ログ、クロック、TCP プロキシモデル

---

LLMSインデックス: [llms.txt](/ja/llms.txt)

---

<!-- Generated by scripts/generate-haproxy-docs.py from pinned upstream text. -->

HAProxy は、マルチスレッドで動作するイベント駆動型のノンブロッキングデーモンです。複数の処理の切り替えをシステムのスケジューリングに任せず、イベントの多重化によってすべての処理をスケジュールします。通常は単一プロセスとして動作するため、システム上で "ps aux" を実行すると "haproxy" プロセスは一つだけ表示されます。ただし、ソフトリロード中に、新しいプロセスと並行して古いプロセスが残りの処理を終えている場合は例外です。このため、strace ユーティリティで動作を簡単に追跡できます。利用可能なプロセッサー数に応じて性能を拡張するため、haproxy はデフォルトで、実行を許可されたプロセッサーごとにワーカースレッドを一つ起動します。明示的に別の設定をしない限り、受信トラフィックはこれらすべてのスレッドに分散され、各スレッドは同じイベントループを実行します。ほぼ線形のスケーラビリティを実現するため、スレッド間の依存関係を必要最小限に抑えるよう細心の注意を払っています。その影響の一つとして、各接続は単一のスレッドで処理されます。したがって、利用可能な処理能力をすべて使うには、少なくともスレッド数と同じだけの接続が必要です。この条件は、ほぼ常に満たされます。

HAProxy は起動時に chroot jail 内に自身を隔離し、その中ではファイルシステムに一切アクセスできないよう設計されています。これは、依存するライブラリ、たとえば libc や libssl などにも当てはまります。直接的な影響として、実行中のプロセスは設定ファイルをリロードして変更を適用できません。代わりに、更新済みの設定ファイルを使って新しいプロセスを起動します。わかりにくい影響としては、libc が実行時に参照しようとするタイムゾーンファイルやリゾルバーファイルが見つからなくなる場合があります。ただし、通常これらは起動後には不要なため、この問題は一般には発生しないはずです。この設計の利点は、HAProxy プロセスが完全にステートレスであり、強制終了後のクリーンアップが不要なことです。プロセスを終了できる方法であれば、どの方法でも適切に処理できます。

HAProxy はログファイルを書き込みません。標準の syslog プロトコルを使ってリモートサーバーにログを送信します。このサーバーは、同じシステム上に配置されていることもよくあります。

HAProxy は、システム時刻を基に予期しないずれを補正した内部クロックを使用し、タイムアウトを管理します。poll() でイベントを待つ時間を制限し、実際に経過した時間を測定することで補正します。実際には、一秒を超えて待つことはありません。そのため、完全にアイドル状態のプロセスを strace で追跡すると、二回の gettimeofday() 呼び出しの間に poll() またはその変種が定期的に呼ばれることがわかります。これは正常でまったく無害な動作です。コストも非常に小さく、システム全体では負荷を検出できないほどであり、異常ではありません。例：

```text
16:35:40.002320 gettimeofday({1442759740, 2605}, NULL) = 0
16:35:40.002942 epoll_wait(0, {}, 200, 1000) = 0
16:35:41.007542 gettimeofday({1442759741, 7641}, NULL) = 0
16:35:41.007998 gettimeofday({1442759741, 8114}, NULL) = 0
16:35:41.008391 epoll_wait(0, {}, 200, 1000) = 0
16:35:42.011313 gettimeofday({1442759742, 11411}, NULL) = 0
```

HAProxy は TCP プロキシであり、ルーターではありません。カーネルが検証した確立済みの接続を扱い、パケットそのものや、他の状態のソケット、たとえば SYN_RECV や TIME_WAIT 状態のソケットを扱うことはありません。ただし、そのようなソケットの存在がポートへのバインドを妨げる場合はあります。受信接続の受け付けと送信接続の開始はシステムに依存します。その直接的な結果として、転送される接続の両側で観測されるパケットには対応関係がなく、サイズ、個数、さらにはアドレスファミリーまで異なる場合があります。接続は LISTEN 状態のソケットからしか受け付けられないため、HAProxy がリッスンしているソケットはすべて、"netstat" ユーティリティでリッスンソケットを表示すれば必ず確認できます。例：

```haproxy
# netstat -ltnp
```

Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State
PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:\* LISTEN 1629/sshd tcp 0 0 0.0.0.0:80 0.0.0.0:\* LISTEN
2847/haproxy tcp 0 0 0.0.0.0:443 0.0.0.0:\* LISTEN 2847/haproxy
