[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で起こる有名な問題みたいですね。

数人がテストする分には目に見えたエラーが起こるものでもなく、負荷試験の際に初めて気づけた現象だったので、負荷試験の大事さを改めて実感した出来事でした。

参考