(@hokaccha)です。クックパッドのアプリには「料理きろく」という機能があります。モバイル端末から料理画像のみを抽出して記録することで食べたものが自動的に記録されていくという機能です。今回はこの料理きろくで画像判定をおこなっているバックエンドのアーキテクチャについて紹介します。実際に判定をおこなう機械学習のモデルのはなしは以下の記事に書かれているのでそちらを参照してください。クックパッド開発者ブログまた、以下のスライドでも料理きろくのバックエンドについて紹介されているのでこちらも参照してみてください。処理の概要ざっくりとした画像判定のフローとしては、次のようになります。クライアントアプリは端末内の画像を判定用に縮小してサーバーにアップロードするサーバーはアップロードされた画像を機械学習を用いて料理画像かどうかを判定するクライアントアプリは判定結果を受け取るクライアントアプリが結果を受け取った後にオリジナルの画像をアップロードしたり、RDBMSにデータを保存するといった処理もありますが、今回は判定処理をクライアントアプリが受け取るまでの流れに絞って解説します。初期のアーキテクチャプロトタイプの段階ではこの処理を単純に料理画像判定用のHTTPのAPIエンドポイントを用意し、そこに画像をアップロードして判定処理を行い、結果をレスポンスで返すという構成で実現していました。APIはRailsとUnicornで動いているサーバーで、その後ろに実際に判定をおこなうPythonのサーバーがたっていてRailsのアプリケーションはそこと通信しています。この処理は画像アップロードに加えて、料理画像判定の処理にディープラーニングを用いているのでそれなりに重たい処理になります。APIサーバーで利用しているUnicornは仕組み上プロセスがリクエストを処理している間他のリクエストをブロックするため、大量のアクセスがきた場合にI/O待ちによりworkerを使い切ってしまいます*1。機能の性質上、端末にある画像をすべてアップロードする*2ので利用者が増えると判定の処理が大量にくる可能性は高かったため、アーキテクチャを変更する必要がありました。現状のアーキテクチャそこでシステムの安定性を高めるため、以下のような方法を取ることにしました。画像はAPIサーバーにアップロードせず、S3に直接アップロードするサーバー側は料理画像の判定処理をバックグラウンドワーカーで非同期に行うAPIサーバーで重い処理を受けないようにすることでアクセスが集中してもAPIサーバーが詰まらないようにし、バックグラウンドワーカーをスケールアウトさせればサービスがスケール可能になるアーキテクチャを目指しました。他にもI/O多重化ができるサーバーを導入するであったり、コストを覚悟でUnicornのサーバーをスケールアウトするという方法も考えられますが、今回は社内のノウハウなども加味して一番安定して稼働できそうという判断のもと、このアーキテクチャを採用しました。最終的な構成としては次のようになります。順に説明していきます。S3に直接画像をアップロードするまず、画像アップロードの負荷を軽減するため、S3に直接アップロードすることにしました。URLを利用しています。Serviceクライアントがアップロード処理を開始するときにAPIサーバーにリクエストし(1)、アップロード可能なS3のURLを取得します。このときAPIサーバーはRDBMSにレコードを作成し、アップロードの状態管理を開始します。クライアントアプリは返ってきたURLに対して画像をアップロードすることでS3に画像がアップロードされます(2)。Notificationsという機能があります。Serviceこの機能を使うと、S3にファイルアップロードされたり、変更されるといったイベントが発生されときに、特定のサービスに通知を送ることができます。これを利用し、S3にファイルがアップロードされたときにSQSにエンキューが行われるようにします(3)。バックグラウンドワーカーの処理バックグラウンドワーカーはSQSのキューをポーリングしていて、エンキューされたメッセージはバックグラウンドワーカーがデキューすることで処理を行います(4)。メッセージのペイロードにはS3にアップロードされたオブジェクトのキーなどの情報が入っているので、その情報を元にバックグラウンドワーカーはS3からアップロードされた画像を取得し(5)、機械学習による判定を行い(6)、結果をAPIサーバーにHTTPで送信し(7)、メッセージの処理を完了させます。このワーカーはPythonで書かれていて、hakoを利用しECS上で動いており、オートスケールの設定もhakoでおこなっています。最後にクライアントアプリは結果をAPIサーバーから取得(8)してフローは終了です。処理を非同期にした場合に難しいのがこの結果の取得です。同期的に判定ができるのであれば、クライアントアプリは判定結果が返ってくるのを待ってから次の処理に進めばいいのですが、非同期の場合はいつ処理が終わるかクライアントアプリにはわかりません。今回はクライアントアプリが定期的に結果取得のAPIエンドポイントにリクエストすることで結果を取得するようにしています。料理きろくという機能はユーザーが写真を撮って、後で見た時に自動で写真が記録されている、という機能なのでそのケースではリアルタイム性が求められないので数十分に一回程度のリクエストで後から結果が取得できれば問題ありません*3。クライアントアプリでそういった処理を定期実行するのは簡単ではなく、様々な苦労がありました。詳しくは料理きろくのAndroidの実装を行った吉田の以下の資料にまとまっています。まとめ料理きろくの料理画像判定部分のアーキテクチャについて解説しました。現時点で一日あたり約50万枚以上の画像を判定していますが、大きな問題はなく安定して稼働しています。基本的にはよくあるジョブキューを利用した非同期処理のアーキテクチャですが、S3やSQSはこういったシステムを組むのにとても便利です。最近ではモバイル端末でも機械学習のモデルが動くようになってきています。実用段階まではいっていませんが、それが実現すればこのようなシステムは一切いらなくなり、クライアントの実装も非常にシンプルになるので、できるだけ早く実現してこのシステムがいらなくなる日がくればよいと思っています。13:25料理画像判定のためのバックエンドアーキテクチャTweet関連記事2019-06-17レシピ検索を支えるレガシーでクリティカルな大規模バッチを刷新した話こんにちは、会員事業部の新井です。〜クックパッドにおける研究開発のサービ...こんにちは!人事部の冨永です。使ったセキュリティログ検索基盤の構築サービス特性にあった検索システムの設計戦略クックパッド採用説明会「クックパッドはサービスの作り手を採用したいんです。/*}*/スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。