概要
Rubyおよびすべてのラック互換フレームワーク向けの高性能ウェブサーバー Puma がメジャーバージョン 8.0 をリリースした。今回のリリースはIO並行処理の抜本的な改善を中心に据えており、高負荷な本番環境での運用効率を大きく引き上げることを目的としている。長年の課題だった「スレッドプールの上限に達するとIOバウンドなリクエストが詰まる」という問題に対し、新たなAPI設計で解決策を提示した点が最大のハイライトだ。
主要な新機能
IOバウンドリクエストの動的処理
最も注目される新機能が、env["puma.mark_as_io_bound"] APIと max_io_threads 設定の組み合わせによるIOバウンドリクエストの超過処理機構だ。従来のPumaはスレッドプールの上限(max_threads)を超えたリクエストをキューイングするしかなかったが、Puma 8.0ではリクエストハンドラがそのリクエストをIOバウンドとしてマークすることで、スレッドプール上限を超えた追加スレッドで処理できるようになった。データベース待ちや外部APIコールが多い混合ワークロード環境で特に効果を発揮する。
動的スレッドプール更新
新たに update_thread_pool_min_max APIと ServerPluginControl が導入され、サーバーを再起動せずにランタイムでスレッドの最小・最大数を変更できるようになった。トラフィック変動に応じてスレッド数をオンザフライで調整するオートスケーリング実装が容易になる。
モード固有設定フック
シングルモードとクラスターモードそれぞれに専用のDSLフック(single / cluster)が追加された。デプロイ形態ごとに異なる設定を一つの設定ファイル内でクリーンに記述できるようになり、設定管理が簡潔になる。
シャットダウンデバッグの強化
shutdown_debug オプションに on_force が追加され、グレースフルシャットダウンではなく強制シャットダウン時にのみスレッドバックトレースをダンプするよう制御できるようになった。通常運用のログを汚さず、問題発生時のみ詳細情報を記録できる。
Linux/JRuby向けシグナル対応
SIGINFO未対応のLinux/JRuby環境でSIGPWRを使ってスレッドバックトレースダンプを呼び出せるようになり、プラットフォーム間でのデバッグ体験が統一された。
パフォーマンス改善
JRuby向けのHTTPパーサーが最適化された。ヘッダーキーの事前割り当てと完全ハッシュルックアップ(perfect hash lookup)の採用、メモリコピーの削減により、JRuby環境でのパース性能が向上した。
また、全Ruby実装共通の改善として、str_headers でダウンケース済みヘッダーキーをキャッシュすることで冗長な String#downcase 呼び出しを排除し、レスポンスごとのアロケーションが約50%削減された。大量リクエストを捌くサービスではガベージコレクション圧力の軽減が期待できる。
破壊的変更と移行上の注意点
Puma 8.0では本番環境のデフォルトバインドアドレスが 0.0.0.0(IPv4)から ::(IPv6)に変更された。IPv6が利用できない環境では自動的に 0.0.0.0 にフォールバックするが、ファイアウォール設定やリバースプロキシの設定によっては動作が変わる可能性があるため、アップグレード前に確認が必要だ。
バグ修正としては、fork_worker 利用時にフェーズ再起動でワーカー0が古い状態のまま置き換わらない問題が解消された。