プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

Google Cloud Storageのモバイル対応は残念な点 およびAmazon Cognitoはすごいという話

今年も年の瀬、最後は一応技術ブログなのでプログラミングの話題で締めます。

モバイルアプリでユーザが画像や動画を投稿するサービスを作る際、バックエンド側のエンジニアが最も腕の見せどころとなるのはレスポンスの早さです。バックエンドにかぎらず、フロントでもバックグラウンドでアップロードさせるとか、細かいローダーをどのように表示するかで体感速度を向上させるわけです。 Amazonではサイトの表示が10ms(=0.01秒)遅くなると売上が~~という話がよくあります。というわけで多くのサイトは200msとか目標を決めてサーバのレスポンスをなるべく早く返しています。だから遅くて1秒、2秒かかるサイトはあっても10秒以上かかるサイトはあまりありません。(ここで言ってるのはサーバの速さです)

一方でモバイルアプリのアップロードはそれとは違い、15秒撮影した動画をアップロードするのに1秒2秒で済むということはありません。iPhone6で加工してない動画を撮影すると1秒あたり2~3MBになりました。 この数字だと回線状態が悪いと10秒とか20秒、あるいはもっとかかるくらいのサイズなのでアップロード中の離脱が増えてしまいます。

モバイルから直接アップロードする

画像や動画をアップロードする際、自社のサービスのサーバ(以降APIサーバ)に送って保存+リサイズ等行うのが多いみたいですが、この方法だとAPIサーバからさらにストレージサービス(s3やGoogle Cloud Storageなど)への転送時間がかかってしまいます。 もちろんこれを非同期にすることは可能ですが、今度はAPIサーバに動画・画像の転送処理というバッチ的な機能を持たせる必要があります。これは例えばRailsAPIを書いてる時、APIサーバ群とバッチ(ActiveJobなど)サーバ群の構成を分けたいときにAPIが一部でバッチ的な役割も担う必要があって見通しが悪くなります。

そこで理論上、モバイルアプリが直接ストレージサービスに画像等をアップロードしてから、そのURLをAPIサーバに送り、さらにバッチサーバでリサイズ等処理をするのが無駄のない処理になります。

このことを言ってくれてるのがこちらの記事です。

qiita.com

で、ここからが本題なんですがs3でできるならCloud Storageでも同様にできるだろうと思い資料を探してみました。 ところが、結論から言えばCloud Storageではこれはできません。(間違ってたら教えて下さい)

そもそもCloud StorageのiOSライブラリはいまだにobjc版だったりARC対応してないなどインストールだけでも大変だったんですが、どうやらAPIの権限上の問題でユーザが投稿することを認めていません。

Cloud StorageのAPIについて

f:id:tkot:20151230221822p:plain

APIのキーがいくつかあって混乱します。 まずセキュリティ上、iOS側に渡しても問題のないキーは一番上のiOS APIキーになると思います。(一応DeNAのプラットフォームの友人に聞いて確認しました) そのほか、例えばサーバキーやサービスアカウントのOAuth認証をユーザに渡すとリバースエンジニアリングのリスクがあるわけです。

で、ポイントはiOS APIキーはサービス全体に紐づくデータやユーザデータに対する権限をあまり持っていないということです。iOS APIキーで調べると一番上にはGoogle Mapのサンプルが出てきます。こういうユーザやサービスにあまり直接かかわらないAPIを操作するためのキーだと思われます。

したがってiOS APIキーではCloud Storageに画像をアップロードすることはできません。

もう一つの方法はユーザがアプリ上でGoogleログインして、アプリに対して認可をくれればそこでもらったOAuthトークンでユーザの画像を作ってやることができますがこれは今回のユースケースとは違うので除外します。

試してないのですがサービスアカウントをハードコーディングせず各ユーザに対して動的に付与してやる方式ならうまくできるのかもしれません。

Amazon Cognito

というわけでAmazon Cognitoの出番です。Cognitoは要するに端末ごとにユーザを識別してくれるサービスです。内部的には初回起動時にユニークIDを付与し、keychainに保存しているようです。

で、ここはわりとブラックボックスになっているのでまだ把握できてませんがCognitoを使えばAWS側が端末を識別できているので、こちらが持っているs3に画像をアップロードできます。

試しに使ってみたら非常にカンタンにアップロードできたので、とりあえず今回はこのアップロード限定でs3を使うことにしました。

Cloud Serviceの一本化/併用は考えて行う

私は普段Google Cloud Services一本なんですが、Googleが持ってないものでAWSが先行しているもの、およびその逆が意外とあることを今回痛感しました。例えばEC2 vs Compute Engineなどはさすがに一本化していいと思いますが、各サービスの利点をうまくとりいれつつ、互いが邪魔しあわないようにうまく住み分け/インテグレートしていくチョイスが今後重要になるのではと思います。