記事概要
JVM言語で話題の暖気運転についてJVM系言語(JIT)以外でも暖気運転は効果があるのかを考察した記事です。何かしらのベンチマークを取ったとかではないのでご注意ください。
JVMとの比較にはPythonとかPerlとかLL系言語かつpreforkで動くウェブアプリケーションを想定しています。
結論
結論としては効果があるケースもあるがJVM系言語ほどの効果は得られない(はず)
そもそも暖気運転とは
暖気運転とはコンパイル済みの状態で本番トラフィックの処理が可能になるよう、サービスインの前にアプリケーションを実行すること。サービス起動時にある程度のリクエストを飛ばしておくことで実際のユーザアクセス時にプログラムのコンパイル処理を事前に行うという仕組み
mod_なんちゃらとは
一方LL言語であるPerlをwebで動かす際にmodperlなんかを使ったりする。modperlを使うとインタプリタ的な実行ではなくプログラムは機械語に変換された後、メモリに常駐するようになる。JVM系言語との違いとしてプログラムの実行時にコンパイル処理は不要となっている。
JVMが行う暖気運転の目的であるプログラムの実行時にコンパイルを行う処理がないLL言語でも暖気運転が効果あるのかを考察していく
LL言語で暖気を行うメリット
LL言語で暖気を行うメリットはぱっと思いつく感じだと以下。それぞれ考察を書いていく。
- ディスクアクセスを減らせる
- 外部サービスとのコネクションを事前に張れる
- TCPでのスロースタート問題に対応できる
ディスクアクセスを減らせる
Linuxの基本として一度アクセスしたファイルはメモリが許す限りはページキャッシュというキャッシュに乗ります。一般的にHDDから読むのとメモリから読むのでは(SATA接続HDDとDDR4構成)約100倍程度のRead/Writeに速度差があるのでファイル読み込み時は極力メモリから読むようにしたいです。
webアプリにおける静的ファイルのアクセスではテンプレートファイルなんかが挙げられます。仮に暖気を行っていない場合はプロセスはディスクアクセスを行ってファルを読み込むが暖気を行っておけばメモリ読み出しのみで済むので有利です(プロセスから外部プロセスを生成する際のバイナリ読み込みみたいなケースで大きめのサイズのファイルの場合は体感しやすいかも)。
また、テンプレートファイルが特定ディレクトリの一階層に大量のファイル数が存在する場合は暖気で全てをreadをかけてページキャッシュに乗せなくてもディレクトリをstat(2)しておくのも良さそう。この場合dentryなんかをキャッシュしておけばアクセス時はディスクアクセスは発生するもののファイルシステムのルックアップ処理は軽減できたりするのでメモリ使用量がシビアならそれだけでも効果的(なはず)
外部サービスとのコネクションを事前に張れる
modperlもmodpythonもmodphpもpreforkで動かす場合はプロセス空間が独立していて各プロセスがそれぞれ外部サービスとのコネクションを管理します。connectを暖気で行ってプロセス内で永続化しておけばユーザリクエストは全てconenct済のプロセスが処理するのでconnect分の高速化を行うことができる。(サービスディスカバリ前提のアーキテクチャなんかだと名前解決のコストも馬鹿にならない)
(1) ソケット生成 socket() (2) ソケット接続要求 connect() === ここまでを暖気でやっておけばユーザアクセスは(3)だけで済む (3) 外部サービスのやりとり
例えばMySQLを例に挙げるとTCP 3-way handshake、データベース層のハンドシェイク、データベース層の認証、データベースプロセス側の接続用プロセス/スレッド生成なんかをMySQL側で行った状態でユーザアクセスが来るといった仕組みを作れる。
(ただこれはポスグレみたいなマルチプロセスモデルのDBの場合はDB側に永続化された分だけプロセスが生成されてしまうので負荷量を計測してからやるなどの考慮が必要そう。)
LL言語でpreforkが前提のモデルだとコネクションプールする仕組みが乏しいためこの辺は暖気が効果的な感じがする。この後書いているTCPレイヤでの輻輳制御にも有利となる。MySQL以外でもhttpレイヤでのkeepaliveをしたりしておくことでその辺の認証も飛ばせたりも可能となったりで意外と効果的な感じはする。(ただこの辺は結局どのミドルウェアもオーバヘッドを最小限にする実装してるだろうし正直計測しないと効果の程は全く読めない。。)
TCPでのスロースタート問題に対応できる
TCPではでコネクションを確立した後、データの送信量を徐々に増やすことで効率的に通信するための仕組みが有ります。コネクト直後はウィンドウサイズを小さく送って輻輳が起きなければ次はもっと大きなデータを送るといった感じで通信していきます。
暖気を行うことで前述した外部サービス連携で先にコネクションを貼ってある程度通信しておけばこのスロースタートをバイパスすることが可能となる。
またmodperlやらmodpythonを直接出してるケースじゃなければLBやらproxyサーバとの通信もTCPを使ってるはずなのでインターナルなサービス間でもこのメリットは活きてくる。(keepaliveをOFFってない限りは)
まとめ
結局、大局的にみたらwebシステムの場合はC-S間のネットワークなり描画なりがボトルネックになって詰まるだろうし正直全体の数%を改善したところでって感じはしますが多分それなりに意味はあると思う。ただ暖気が必要なほどシビアならここで挙げたメリットは対策方法が他にもあるのでそっちの方が良いかも。
具体的には
- ディスクアクセスを減らせる -> 静的ファイルはtmpfs使ってメモリに乗せておく
- 外部サービスとのコネクションを事前に張れる -> サービス起動シーケンスに入れよう
- TCPでのスロースタート問題に対応できる -> 同上
構成を変えずに暖気を行いたいケースがあれば使えそう。(多分)