[rails]carrierwaveを使って画像生成しようとしたらCPU使用率100%になる現象にハマった
Ruby2.1.4、Rails4.2.0で確認 carrierwaveを使って画像生成を行うアプリケーション開発を行っていた際に、 abコマンドで負荷テストを行ったところCPU使用率が100%になる現象が発生しました。
高負荷状態であれば、CPU使用率100%になるのもあり得るのですが、マルチコアのサーバにも関わらず1リクエストでテストを行っても、すべてのCPUが使用率100%になってしまうという現象でした。
これは何かおかしいと思い調べてみたところ、結論としてはcarrierwave内部で使用している ImageMagickに問題がありました。
ImageMagickには OpenMPという並列処理を簡潔に書ける仕組みに対応したバージョンがあり、そのバージョンをマルチコア環境で使用している場合に、高負荷になる現象が発生することがあるそうです。
ImageMagickのバージョンを調べてみたところ、やはりOpenMPを使用していました。
convert -version
Version: ImageMagick 6.5.4-7 2014-02-10 Q16 OpenMP http://www.imagemagick.org
Copyright: Copyright (C) 1999-2009 ImageMagick Studio LLC
対応方法としては OpenMP版ImageMagickの高負荷問題の最も簡単な対処法:ImageMagick:Technical tips:Media hubこちらに記載されていた環境変数の設定で負荷を下げることができました。
/etc/environmentに以下を記述し、
# /etc/environment
export OMP_NUM_THREADS=1
unicorn起動時に/etc/environmentを読み込むようにして起動するようにします。
source /etc/environment && cd ${RAILS_ROOT_DIR} && bin/unicorn_rails -c ${UNICORN_CONF} -E ${RAILS_ENV} -D
abコマンドで20ユーザが同時に1リクエストを送るテストを行ってみたところ、以下の結果となり、約22倍の性能改善になりました。
ab -c 20 -n 20 http://xxx.xxx.xxx/api/benchmark
before/after | ab結果 |
---|---|
before | Requests per second: 1.17 [#/sec] (mean) |
after | Requests per second: 26.40 [#/sec] (mean) |
CPUコア数が多いにも関わらず画像処理が高負荷になってしまう場合は、OpenMPの設定を確認してみてください。
公式ページ( ImageMagick: Parallel Execution with OpenMP)の下部に特定環境で不安定になると記載されていました。
こちら、調べるまで気付かなかったのですがImageMagickで起こる有名な問題みたいですね。
数人がテストする分には目に見えたエラーが起こるものでもなく、負荷試験の際に初めて気づけた現象だったので、負荷試験の大事さを改めて実感した出来事でした。