hello-world
webエンジニアのメモ。とりあえずやってみる。

[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/afterab結果
beforeRequests per second: 1.17 [#/sec] (mean)
afterRequests per second: 26.40 [#/sec] (mean)

CPUコア数が多いにも関わらず画像処理が高負荷になってしまう場合は、OpenMPの設定を確認してみてください。

公式ページ( ImageMagick: Parallel Execution with OpenMP)の下部に特定環境で不安定になると記載されていました。

こちら、調べるまで気付かなかったのですがImageMagickで起こる有名な問題みたいですね。

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

参考


Related #carrierwave

[rails]carrierwaveで保存した画像のurlを取得する

carrierwave 0.10.0 で確認 imageカラムにcarrierwaveで保存した画像を保存している場合、デフォルトのままだとだとurlメソッドを実行してもpublic以下のパスのみで http://~ が設定されていません。

[rails]base64エンコードされた画像をcarrierwaveに保存する

Ruby 2.1.4, Rails 4.1.7 で確認 前回はcarrierwaveを使ってPOSTされた画像ファイルの保存を行うAPIを作ってみました。

[Rails]carrierwaveのcallbackをskip

Railsで画像アップロード機能を作る際に欠かせないgemと言えば carrierwave ですが、save時にcarrierwaveのcallbackをskipしたい場合の対応方法をメモしておきます。