Puma v8.0.0リリース: IPv6デフォルト化とスレッドプール制御の強化
Puma 8.0.0(コードネーム "Into the Arena")がリリースされました。デフォルトバインドアドレスのIPv6化、IOバウンドリクエストのスレッドプール超過を可能にする新API、ランタイムでのスレッド数変更など、混合ワークロードの扱いを中心に大きな強化が加わっています。
背景
Puma 7系まで、スレッドプールの上限を超えて並列度を高める手段や、シングルモード・クラスターモードを一つの設定ファイルで明確に表現する方法が不足していました。特に、ほとんどがI/O待ちとなる「IOバウンドリクエスト」がCPUバウンドなリクエストとスレッドを奪い合う問題は、混合ワークロードを持つアプリケーションにとって課題でした。
また、デフォルトバインドアドレスが 0.0.0.0(IPv4)であり続けていたことで、IPv6環境での設定を別途行う必要がありました。これらの課題に対し、v8.0.0は複数の機能追加と一つの破壊的変更によって応えています。
技術的な変更
IOバウンドリクエストのスレッド上限超過
IOバウンドリクエストが通常のスレッド上限を超えて処理できるようになりました。 新たに追加された max_io_threads 設定と env["puma.mark_as_io_bound"] APIを組み合わせることで、アプリケーション側からPumaにIOバウンド性を通知できます(#3816、#3894)。
設定例とRackアプリケーション側の使用例は以下のとおりです:
threads 0, 5
max_io_threads 5
run lambda { |env|
env['puma.mark_as_io_bound'].call
report = SlowReportService.fetch
[200, { 'content-type' => 'application/json' }, [report]]
}
このAPIは主にフレームワーク作者や、特定のリクエスト種別が極めてIOバウンドであることを把握しているミドルウェア向けに設計されており、アプリケーションレベルでの一般利用は推奨されていません。
ランタイムでのスレッドプール変更
Puma::Server#update_thread_pool_min_max が追加され、スレッド数をランタイムで変更できるようになりました(#3658)。 プラグインやフック内からは Puma::ServerPluginControl 経由で同様の操作が可能です。
# プラグインや信頼できる in-process 統合から
server.update_thread_pool_min_max(min: 2, max: 12)
シングル・クラスターモード別設定ブロック
新しい single と cluster DSLブロックにより、単一の設定ファイルでモード別設定を明確に記述できます(#3621)。 これらのブロックは設定ファイルのロード後に実行されるため、config/puma.rb 内に if ロジックを散在させる必要がなくなります。
デフォルトバインドアドレスのIPv6化(破壊的変更)
デフォルトのプロダクションバインドアドレスが 0.0.0.0 から :: (IPv6) に変更されました(#3847)。 ただし、非ループバックのIPv6インターフェースが利用可能な場合のみ :: が使用され、IPv6が利用不可の場合は 0.0.0.0 にフォールバックします。既存のIPv4環境でのデプロイには影響がないよう配慮されていますが、IPv6環境では動作確認が必要です。
パフォーマンス改善
str_headers でダウンケース済みヘッダーキーをキャッシュすることで、レスポンスあたりの String#downcase 呼び出しを排除し、アロケーションを約50%削減しています(#3874)。 また、JRubyのHTTPパーサーではヘッダーキーの事前アロケーション、パーフェクトハッシュルックアップ、メモリコピー削減が実施されました(#3838)。
その他の変更
-
SIGPWR対応: LinuxのJRubyでは
SIGINFOが利用できないため、スレッドバックトレースダンプにSIGPWRを使用するようになりました(#3829) -
on_forceオプション:shutdown_debugにon_forceオプションが追加され、強制シャットダウン時のみスレッドバックトレースを出力する設定が可能になりました(#3671) -
fork_workerフェーズドリスタートの修正: ワーカー0が置き換えられた後に古いワーカーからフォークしてしまうバグが修正されました(#3853) - セキュリティサポートポリシー更新: サポート対象が 6.x から 8.x に移行し、7.x と 8.x の最新リリースがサポート対象となりました
設計判断
env["puma.mark_as_io_bound"] という呼び出し可能オブジェクトをRack envに注入するアプローチは、Rackのインターフェース規約に沿った設計です。 アプリケーションやミドルウェアがPumaの内部APIに直接依存することなく、標準のRack env辞書を通じてサーバーに情報を伝達できます。これはPumaが既存の env["puma.socket"] などで採用してきたパターンの延長線上にあります。
IOバウンドスレッドをアプリケーション層から識別させる設計は、Pumaが「リクエストがIOバウンドかどうか」を推測するより、アプリケーション側の知識を活用するという判断を示しています。 CPUバウンドとIOバウンドの境界はワークロードに依存し、Puma単独では判断できない情報です。これをAPIとして公開することで、フレームワーク作者がワークロード特性に応じた最適化を実装できるようになります。
まとめ
Puma 8.0.0は、混合ワークロードへの対応強化を中心に、スレッドプール管理の柔軟性を大きく向上させたメジャーリリースです。破壊的変更はデフォルトバインドアドレスのIPv6化のみに抑えられており、IPv6環境への対応状況を確認のうえアップグレードすることで、IOバウンドリクエストとCPUバウンドリクエストの共存、ランタイムでのチューニングといった新たな選択肢を得られます。