kickflow Tech Blog

株式会社kickflowの開発チームによるブログ

Active Storageのダイレクトアップロードのパフォーマンスチューニング

こんにちは。エンジニアの森本です。

kickflowでは、申請するチケットに対してファイルを添付することができます。これらをActive Storage のダイレクトアップロードを使って実現しています。 以前からファイルを大量に添付したチケットを申請すると、タイムアウトが発生してしまう問題がありました。APMサービスを見てみると、ファイルをダウンロードしている処理がありました。 今回は、ダイレクトアップロードを利用していてファイルを大量にアップロードしたときにタイムアウトが発生しないように行った工夫を共有したいと思います。

ダイレクトアップロードとは

ダイレクトアップロードとは名前の通り、S3やGoogle Cloud Storageなどのクラウドストレージにブラウザから直接アップロードする機能です。サーバに直接ファイルをアップロードしないため、サーバへの負荷や転送量を抑えられる手法で、Herokuでも推奨されています

railsguides.jp

Active Storage のダイレクトアップロードを利用するとサーバにファイルをアップロードせずattachを行えると思いませんか? 実は、サーバ側でファイルのダウンロードを行っているんです。

なぜファイルをダウンロードしているのか

active_storage_blobsテーブルの metadata カラムはJSONで保存されていますが、その中にidentifiedという要素があることをご存知でしょうか? identifiedは、ファイルのContent-Typeを判定する処理の完了を示すフラグのようです。

具体的には、 以下で行われています。

github.com

この処理で、Content-Typeの判定のために、4KB分だけファイルをダウンロードしています。

この処理はファイルをattachした際に自動的に呼び出されます。通常の利用では4KBのファイルダウンロードでは問題になりにくいです。

しかしkickflowでは、以下の2点により問題が顕在化しました。

  • 1回の申請で100件までの添付ファイルをアップロード可能
  • HerokuはUSリージョン、S3は東京リージョンにありファイルダウンロードに時間がかかる

1ファイルのダウンロードに200ミリ秒前後かかるため、ファイルダウンロードだけで20秒程度かかってしまいます。

解決方法

弊社では、ダイレクトアップロードが完了したファイルから先行してContent-Typeの判別処理を走らせることにしました。 具体的には、ActiveStorage::Blob::Identifiable#identify を呼び出すことでContent-Typeの判定を行うことができます。 これにより、attach時に、ファイルダウンロードが行われず処理時間を短縮することができました。

blob = ActiveStorage::Blob.find_signed!(params[:signed_id])
blob.identify unless blob.identified?

添付ファイルをダイレクトアップロードにしているのに、ファイルダウンロードが発生、タイムアウトしてしまい困っている方の参考になれば幸いです。

We are hiring!

kickflow(キックフロー)は、運用・メンテナンスの課題を解決する「圧倒的に使いやすい」クラウドワークフローです。

kickflow.com

サービスを開発・運用する仲間を募集しています。株式会社kickflowはソフトウェアエンジニアリングの力で社会の課題をどんどん解決していく会社です。こうした仕事に楽しさとやりがいを感じるという方は、カジュアル面談、ご応募お待ちしています!

careers.kickflow.co.jp