0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHP動かすの面倒くさいイジりを解決してみた

Posted at

概要

  • RustでPHPサーバーを作った(実験)
  • libphp, PHP-FPM, 静的ファイル配信をリクエストごとに動的に切り替える(既存の単一バイナリソリューションにはない実装)
  • Nginx + PHP-FPMの1.8〜2.1倍のパフォーマンス
  • 実運用性の証明として67,000リクエスト処理でエラー0%、メモリ使用量22MB
  • TUIモニター内蔵でリアルタイム監視をSSH経由でも監視可能に

なぜ作ったのか

mod_phpだろうがphp-fpmだろうがnginx + リバースプロキシだろうがapacheだろうがPHPerは何も困っていない。
ログを追う面倒さ、そしてFirewallの設定なりパケットフィルタの設定はまた別になり、WAFは...と多岐にわたりすぎている問題から目を背ければね。
Claude Code on the Webが無料で$1000利用できる機会を活かすべく、小難しいことはAIに任させて動くもの作ってみるかぁと長き宿縁に終止符を打つべく作成した。

他と何が違うのか

1. 適材適所のハイブリッドアーキテクチャ

単一バイナリ製品はFrankenPHPなりSwooleなりRymfonyがあるけれどもアプローチが一つしかない。これにはPHPerは納得いかない。libphpでもphp-fpmでも資源は有効に使うべきだと思いハイブリッドバックエンドアーキテクチャとしてリクエストパスに応じてlibphpを直接実行するのかPHP-FPMにプロキシするのか直接配信するのかを単一バイナリにやらせている部分が唯一無二であります。

2. TUI Monitor内蔵

ターミナルでリアルタイムに監視を行え、SSH経由でリモート監視も可能なTUIビルドイン機能。
こんなん
tui.png

リモート監視する場合は踏み台経由するなりして

ssh production-server "fe-php monitor --socket /var/run/fe-php-admin.sock"

ここが結構気に入っています。
Nginxのログ見るとかApacheのログ、PHP-FPMのログを見るなど忙しいですからね。
ログの自動解析つけてあるので、問題となりそうである部分を素早く察知できます。

tui-analysis.png

3. API経由での完全統合

# 設定リロード
echo '{"command":"reload_config"}' | socat - UNIX-CONNECT:/var/run/fe-php-admin.sock

# IPブロック
echo '{"command":"block_ip","ip":"192.168.1.100"}' | socat - UNIX-CONNECT:/var/run/fe-php-admin.sock

# ステータス確認
curl http://localhost:9001/api/status | jq .

とても簡単です。
OSレベルでipfw add deny ip from 192.168.1.100 to any 80したり
ipfw listでルール確認して削除するなんて面倒から解放されます。
適材適所ってことでfail2banを利用するのも良いとは思うけれども、あっちこっちに設定書いてどこで制御しているのかをサーバー毎に各設定を読め!というのは...あまりにもつらい。

パフォーマンス

テスト環境: Apple M1 Max、32GB RAM、macOS Sequoia 15.1

高並列負荷(500 RPS目標、並列50)
サーバー 実測RPS Nginx比 p50レイテンシ p99レイテンシ
Nginx + PHP-FPM 209.86 1.0x 4ms 10ms
fe-php (Hybrid) 374.80 1.79x 2ms 3ms
ストレステスト(1000 RPS目標、並列100)
サーバー 実測RPS Nginx比 p50レイテンシ p99レイテンシ
Nginx + PHP-FPM 201.18 1.0x 4ms 11ms
fe-php (Hybrid) 429.76 2.14x 1ms 5ms

FastCGIプロトコルのオーバーヘッドないのとプロセス間通信ないのでそれはそうなんですけど、早いは正義ってことで。

実運用...耐えられるのか?!

耐えられる。
上述の通りMacOSでの検証ですが、Embedded PHP + FastCGIをハイブリッド利用して4workerで以下のテストを行った。

1. 基本負荷テスト(100 RPS)

=== 結果 ===
実測RPS:    84.24 RPS
総リクエスト: 2,528
成功率:      100.00%
エラー:      0件

レスポンスタイム:
  p50:  2ms
  p75:  2ms
  p95:  3ms
  p99:  5ms
  max:  18ms

安定

2. 中負荷テスト(500 RPS)

=== 結果 ===
実測RPS:    339.70 RPS
総リクエスト: 10,192
成功率:      100.00%
エラー:      0件

レスポンスタイム:
  p50:  2ms
  p75:  3ms
  p95:  3ms
  p99:  5ms
  max:  22ms

安定

3. 高負荷テスト(1000 RPS)

=== 結果 ===
実測RPS:    307.48 RPS
総リクエスト: 9,225
成功率:      100.00%
エラー:      0件

レスポンスタイム:
  p50:  3ms
  p75:  3ms
  p95:  4ms
  p99:  7ms
  max:  71ms

安定。とはいっても時間が短いので

4. 5分間安定性テスト

=== 結果 ===
実測RPS:    151.99 RPS
総リクエスト: 45,597
成功率:      100.00%
エラー:      0件

レスポンスタイム:
  p50:  3ms
  p75:  3ms
  p95:  6ms
  p99:  11ms
  max:  94ms

問題なし。

5. メモリ使用量

$ ps aux | grep "fe-php serve"
USER   PID  %CPU  %MEM  VSZ     RSS
ORE    xxx   0.0   0.1  435MB   22MB

22MB
Nginx+PHP-FPMでは250MB程度必要としていたので中々削減されたのではないかと思う。

# Nginx
worker_processes: 4
worker_connections: 1024
keepalive: 65

# PHP-FPM
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

6. レスポンスの一貫性

10回連続でリクエストを送信したときのレスポンスタイム

2.990ms
2.585ms
2.609ms
2.495ms
3.431ms
2.477ms
2.404ms
2.821ms
3.042ms
2.449ms

平均: 2.73ms
標準偏差: 0.35ms

ということで、実運用性はあると言えます。
libphpと密結合なので気軽に実用は出来ないけどね。

設定ファイル1個で全部動く良さ

以下が内蔵されていることにより

  • HTTPサーバー
  • PHP実行環境
  • 静的ファイル配信
  • WAF
  • レート制限
  • メトリクス
  • 管理API
  • TUI Monitor
  • TLS/SSL
  • CORS
  • グレースフルシャットダウン

設定ファイル一つメンテナンスすればいい良さがある。

[server]
host = "0.0.0.0"
port = 8080
workers = 4

[php]
libphp_path = "/usr/local/lib/libphp.so"
document_root = "/var/www/html"

[backend]
enable_hybrid = true
default_backend = "embedded"

[admin]
enable = true
unix_socket = "/var/run/fe-php-admin.sock"
http_port = 9001

[waf]
enable = true
mode = "block"

実際の使い方イメージ

Nginxでやっても同じようなもんなのですが、一元管理できるのが味噌です。

皆大好きWordPress

# 公開ページ → 高速なEmbedded
[[backend.routing_rules]]
pattern = { type = "prefix", value = "/" }
backend = "embedded"
priority = 50

# 管理画面 → 安定性重視のFastCGI
[[backend.routing_rules]]
pattern = { type = "prefix", value = "/wp-admin/" }
backend = "fastcgi"
priority = 100

# アップロード画像 → 直接配信
[[backend.routing_rules]]
pattern = { type = "prefix", value = "/wp-content/uploads/" }
backend = "static"
priority = 90

セキュリティ機能

WAF(Web Application Firewall)

[waf]
enable = true
mode = "block"  # または "detect"

[waf.rate_limit]
requests_per_ip = 100
window_seconds = 60
burst = 20
  • SQLインジェクション検出
  • XSS検出
  • パストラバーサル検出
  • カスタムルール定義
  • レート制限
  • 動的IPブロック
  • ログの自動解析

動的IPブロック

# IPブロック
echo '{"command":"block_ip","ip":"192.168.1.100"}' | socat - UNIX-CONNECT:/var/run/fe-php-admin.sock

# ブロック解除
echo '{"command":"unblock_ip","ip":"192.168.1.100"}' | socat - UNIX-CONNECT:/var/run/fe-php-admin.sock

ログ探しからの解放

  • 従来
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
tail -f /var/log/php-fpm/error.log
...
  • fe-php
fe-php monitor

これだけ

ログ自動分析機能によって以下を素早く確認。

  • エンドポイント別の統計
  • 遅延リクエストの検出
  • 不審なアクティビティ検出

実際にはもっと詳細に様々なログを追うことになりますが,素早くあたりを付けられることが大きいと思います。

まとめ

従来の問題

  • 設定, ログの分散
  • オーバーヘッド
  • 監視が煩雑

fe-phpの解決策

  • 単一バイナリ、単一設定
  • TUI統合監視
  • ハイブリッドバックエンド

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?