シンクロ・フード エンジニアブログ

飲食店ドットコムを運営する、株式会社シンクロ・フードの技術ブログです

Tomcatを高速に起動する

こんにちは、シンクロ・フードの大久保です。最近はAWSのLambdaを触っています。近々、そのネタもブログにしようと思っています。

さて、今回はTomcatの起動高速化のお話しをしようかと思います。Railsもやっていますが、なんだかんだ言って弊社はTomcatとの付き合いが長いので…。

まず、Tomcatの起動高速化する方法を紹介する記事としては、以下のWikiが有名です。
https://cwiki.apache.org/confluence/display/TOMCAT/HowTo+FasterStartUp

今回はこの記事を軽く紹介していく、という、新しいことが特にあるわけでもない記事です…。
とはいえ、元記事を読んだことが無い方には参考になるかもしれませんので、もしこの記事を読んで興味が湧いたら、元記事を読んでみてください。

尚、弊社の本番環境で運用されているTomcatは、サーバを切り替えながら再起動をする仕組みができているため、起動速度を上げたいというニーズがなく、本番環境で適用している設定はありません。弊社では開発環境や、テスト環境などで設定をしています。

高速化手法 その1:web.xmlにmetadata-complete=trueとabsolute-orderingを設定する

Wikiによると、WEB-INF/web.xmlに以下の設定を加えることで、高速化される、とのこと。
1. web-app要素に、metadata-completeという属性を設定し、値をtrueにする
2. absolute-orderingという空要素を追加する

そもそも、Servlet3.0にて追加された、各種便利機能(Servlet開発を楽にするアノテーションなど)のために、Tomcatは起動時にJavaのclassファイルをscanするのですが、これが起動速度に影響します。弊社のようにSeasar2を使っている場合、Servlet3.0で追加された機能が無くても開発に支障はでないため、scanが不要だったりします。
この設定は自身のプロジェクトにあるclassファイルやライブラリをscanしないようにさせる設定です。

適用例はこんな感じ

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"  
version="2.4" metadata-complete="true">  
  
    <absolute-ordering />  

実際に手元のPC(Intel Corei7-4750HQ、メモリ16GB)にある弊社サイト「飲食店.COM」の起動時間を適用前/後で比較したところ、起動時に大体6600msくらいかかっていたのが、2300msになりました(10回起動した平均値)。
ただし、クラスや依存ライブラリの少ないWebアプリケーションで比較すると、ほとんど効果を感じられませんでした。
当然ながら、クラスやライブラリの数が多ければ多いほど効果があるようです。

高速化手法1~4は、この「jarスキャンを減らすことで速度を上げる」という方向性での高速化を行なっています。

高速化手法 その2:不必要なjarファイルを消す

当たり前ですが、不要なjarファイルが無い方がスキャン対象が減って起動速度が早くなります。

高速化手法 その3:jarファイルをスキャンから除外する

Tomcat7の場合、catalina.propertiesに除外するjarを記載することでスキャンするjarファイルを指定できます。

tomcat.util.scan.DefaultJarScanner.jarsToSkip=\  
bootstrap.jar,commons-daemon.jar,tomcat-juli.jar,\  
...(省略)  
除外したいjarファイル.jar  

Tomcat8ではcatalina.propertiesの他に、context.xmlにある要素の下に、要素を追加して除外もできますが、弊社はcatalina.propertiesに設定をしてしまっています。
この手法は個別にスキャンをスキップするjarファイルを指定することができるので、1の手法よりも少し安心感があります。
当然ですが、除外するjarファイルが多ければ多いほど、起動が早くなります。

高速化手法 その4:WebSocketサポートを切る

TomcatでWebSocketを使わない、という場合は、WebSocketを無効化しましょう、という内容です。
実際には、tomcat/libの下にある、tomcat7-websocket.jar、tomcat-websocket.jarなどを消せば良いです。
こちら、ここに言及した高速化手法をまったくしていない環境に対して実施すると、20%ほど起動が高速化します(6600msが4400msくらい)。
ただし、他の手法でjarファイルのスキャンを無効化していると、WebSocket周りのjarスキャンも無効化されているため、jarファイルを消す意味はないです。
つまり、jarのスキャンは無効化したくないけれども、WebSocketは使わない、という場合に有効な手法ですね。

高速化手法 その5:Entropy Sourceをnon-blockingな/dev/urandamを指定する

Tomcatは起動時にSecureRandamを初期化するために、/dev/randamからホストサーバのノイズを集めて乱数生成をするのですが、/dev/randamは十分なノイズが集まるまではブロックをします。こちらを、ブロックしない/dev/urandamを使うことで高速化する、というのがこちらの内容です。
この2つの違いはTomcat起動とは関係なく、様々なブログなどで言及されているので、あまり詳細には書きません。
具体的な指定としては、以下を起動オプションに加えます。

-Djava.security.egd=file:/dev/./urandom  

高速化手法 その6:プロジェクトを並列起動する

一つのTomcatで複数プロジェクトを起動している場合、デフォルトでは一つ一つ直列に起動するのですが、これを並列起動することで速度を上げることができます。
弊社は一つのTomcatで複数サイトを運営しているため、この設定でかなり起動速度が上がっています。
具体的には、Host要素にstartStopThreads属性を追記し、ここに並列起動数を記載します。0を指定すると、CPUのコア数分起動するので、Tomcat以外のアプリケーションがCPUを常時使っていないのであれば、0で良いと思います。
https://tomcat.apache.org/tomcat-8.0-doc/config/host.html

まとめ

Wikiに記載されているのは以上です。地味ーな内容ですが、Tomcat起動が遅くてイライラ…という方がいらっしゃればお試しください。
少しでも興味があれば、元記事を読んでいただくのが良いと思います。
https://wiki.apache.org/tomcat/HowTo/FasterStartUp

シンクロ・フードではエンジニアを募集しています。Tomcat、好きだなあ…という方、是非ご応募ください! もちろんRubyでもWebアプリケーションを書いているので、Java以外でもWebアプリケーション書きたい、という方も募集中です。

www.synchro-food.co.jp