1. Qiita
  2. Items
  3. iOS

個人開発アプリのサーバーサイド環境を金と時間をかけずに用意する方法

  • 864
    Like
  • 1
    Comment
More than 1 year has passed since last update.

この記事はSansanアドベントカレンダー3日目です。

前提

個人でアプリを開発していても、やっぱりなんだかんだサーバーサイドが必要になる機会ってあると思います。ただ、注力したいのはやっぱりアプリ側の開発なのでできるだけサーバーサイドにはコストをかけたくない、そんなときどうすれば、、、みたいな話です。

基本的には、

  • 金をかけたくない
  • 時間をかけたくない
  • でもサーバーサイド用意したい

という前提で雑にサーバーサイド環境を用意する場合の話です。

作ったアプリなど

最近は放置気味になっていますが、下記のようなアプリをこれまでにリリースしました。いずれも2人で開発した個人アプリで、アプリに注力しながらもそれなりに頑張ってサーバーサイド側も用意しました。瞬間最大風速では、1000リクエスト/秒くらいのアクセスがあっても特に負荷などの問題も起きず、一応正常に動作してました。

ヒミツのアルバム(写真管理アプリ)
https://itunes.apple.com/jp/app/himitsunoarubamu.../id662735705?mt=8

にゃんこタウン(箱庭系町作りゲーム)
https://itunes.apple.com/jp/app/nyankotaun/id845923130?mt=8

サーバーサイド環境を用意すると何が嬉しいのか?

そもそもなくてもいいじゃんというのも実際あります。かけられる時間によってはもちろん、クライアント完結なアプリにするのも全然アリな選択だとは思います。個人的にはサーバーサイドを用意しておいてアプリ運営で嬉しかった点は、大体下記のような感じです。

1.プッシュ通知を飛ばせる

サーバーサイドを用いずローカル通知だけでユーザーの呼び戻し試作を行うというのもコスパ的には悪くない選択肢ではあります。例えば、3日以上アプリが起動しなかった場合のみ「戻ってきてほしいニャン」みたいな通知を送る、というのはクライアントサイドだけでも可能な施策です。

iOSのローカル通知・UILocalNotificationの設定まとめ

しかしながら、アプリをアップデートしたときにお知らせを送る、特定のキャンペーンを開催中のときのみお知らせを送る、別のユーザーに何かアクションをされたときに通知を送る、などの施策を行うためにはやはり何かしらの手段でサーバーサイド側の用意をする必要があります。

2.アプリの細かな調整をリアルタイムに行うことができる

例えばユーザー体験を損ねずに収益を最大化するためにどういう組み合わせでどの広告を出せばよいのかリアルタイムに調整する、広告を出してみたけど収益的には微妙だったのでユーザー体験を優先して表示を即時オフにする、なんてことをするためにはやはりサーバーサイドで制御を行う必要があります。

また、期間限定のキャンペーンなどをサーバーサイドのマスタデータを変更するだけで設定する、といったことも可能です。具体的な例だと、上述のヒミツのアルバムというアプリでは季節限定で条件を満たすと新たな表示テーマをダウンロードできる!というキャンペーンの制御を、サーバー上のyamlファイルで指定できるようにしています。ゲームの難易度やクリア条件の調整なども、同様にサーバーに置いたマスタデータを変更することで、リアルタイムに調整することが出来るようになります。

リアルタイムにこのあたりの設定を調整することが出来るのは、特にアップデートに審査期間が必要なiOSの開発では大きなメリットです。

3.アプリのログを取得することができる。

どのようにアプリが使われているかを知ることが出来れば、より良い体験をユーザーに提供することが出来るようになります。例えば、チュートリアルのどの部分でユーザが抜け落ちているのかを知ることが出来れば、アプリの定着率を大きく改善することが出来る可能性があります。

また、ある機能をユーザーが利用するときにどういう動線からその機能を訪れているか、というのも重要な指標です。モバイルアプリの画面はそれほど大きくないので、何を切り捨てるかという判断を常に行うことになります。その判断をするときに、ユーザーの行動は非常に重要な判断材料となります。

4.アプリをアンインストールしても状態を保存しておける

ユーザー情報をサーバーサイドに持っておくことで、ユーザーがうっかりアプリをアンインストールしてしまっても復旧してあげることができます。

例えばiOSだとユーザー登録などの処理を実装しなくとも、UUIDの発行とKeychain Servicesを組み合わせることで、端末毎にユーザーをユニークに管理することができます。

参考: http://xoyip.hatenablog.com/entry/2014/06/13/200000

上記のように端末毎にユニークにユーザーを管理しておくと例えばコミュニケーション機能などで悪質な行為を行うユーザーに対してアカウント停止などの措置を行った場合にも有効です。アプリインストール時にUUIDを発行する方式だと、アカウント停止などを行ったとしてもアンインストールして即復活、みたいになってしまうので。。

5.ユーザー同士のコミュニケーション機能を作れる

アプリやゲームを運営してると、ユーザー同士の交流機能が欲しいニャン、うちもソーシャルなゲームにしたい、みたいになるのはよくあることです。

こういったソーシャルな機能については、導入してみると驚くほど継続率が変わることもあり、可能ならば導入してみたい、みたいに思っている開発者の方も多いと思います。こうした機能もやはり、サーバーサイドでの処理無しには実現することが出来ないものです。

クラウドサービス(MBaaS)を使ってサーバーサイドを実現する

世の中の進歩は素晴らしく、実は上述したような機能はほとんどすべて、既存のクラウドサービスを利用することでサーバーサイドのコードを一行も書くことなく実現することが出来ます。

そういったサービスを総称してMBaaS(Mobile Backend as a Service)と世間では呼ぶらしいです。このMBaaSを利用するメリット/デメリットは下記の様な感じです。

MBaaSを利用するメリット
・アカウントを作成してアプリにSDKを導入するだけで簡単にサーバー処理を導入できる
・一定規模のアクセスまでは無料で利用できることが多い
MBaaSを利用するデメリット
・無料だと機能の制限があることが多い
・従量課金の場合、アプリが大きくヒットするとそれなりのお金がかかる可能性がある

下記では、そんな便利なMBaaSをいくつか紹介してみます。

Parse

Parseを利用すると、サーバーサイドのコードを一切書くことなくプッシュ通知やサーバーサイドのデータベースを用意することが出来ます。しかも、負荷対策なんて考えなくても自動でスケールしてくれる素晴らしいサービスです。

アプリのコードを書くだけでParse上で用意されたデータベースの操作も行うことが出来るので、ソーシャルな機能などもサーバーサイドのコードを一行も記述することなく実現可能です。

上述した内容でいうと、1.プッシュ通知4.アプリの状態を保存しておく5. ユーザー同士のコミュニケーション機能、などはParseを利用すれば実現可能です。

参考: 個人のスマホアプリ開発者がParseを使うべき15の理由

また、デバイスにChannel(タグのようなもの)を紐づけることができ、Channelで指定してプッシュ通知することが出来るのも便利です。この仕組みを利用すると、例えばチュートリアルを突破したユーザーにのみプッシュ通知を送る、ゲームをクリアしたユーザーにのみ、新作アプリの通知を送る、などといったことも可能です。

参考:Parse.comを使ったiOSデバイスへのプッシュ通知[ターゲッティング編]

プッシュ通知の開封率が見えるのも地味に便利。自分で運用してた個人アプリでは、プッシュ通知周りは全てParseで管理していました。

Parseのデメリット
現状は改善しているかもしれないのですが、2014年時点では保存されたデータに対する管理画面からの閲覧・操作は非常に不便でした。例えば、特定の条件のデータのみ一括で変更する、管理画面からクエリを発行してデータを閲覧する、などは実現することが出来ませんでした。

ユーザデータを詳細に分析したい場合や、データを一括でバッチ処理する、みたいなことを実現したい場合には素直にRDBを自前で用意して使ったほうが良いかな、という気がしています。

Dropbox

え、アプリ開発にDropbox?って感じですが、個人開発など小規模なものなら意外と使えちゃいます。あまり知られてないのですが、DropboxはPublicフォルダに置いたファイルにはURLが付与され、サーバーにアップロードしたファイルと同様にどこからでもアクセスすることが出来ます。

つまり、Dropboxのpublicフォルダに調整したい設定を全てJSON形式で書いて配置してしまえば、前述した2. アプリの細かな調整をリアルタイムに行うことができるという点は実現できちゃうわけです。

参考: Using Dropbox to Host Files for your email and website

JSONについては、手動でいじるとなるとさすがに大変ですが、下記に紹介されているようなエディタソフトを利用することで容易に操作することが出来るようになります。

JSONをもっと使うために知っておきたいJSONエディタ×8選

このようなエディタで設定のJSONを書いて、Dropboxの中のPublicディレクトリにファイルをぽいっと放り込んでそのURLをアプリから叩くだけ、というお手軽さ。

Dropboxのデメリット
そもそもDropbox側が意図した使い方でないことは確かなので、規模の大きくなりそうなプロダクトでは絶対使わないようが良いです。下記に公式のヘルプに書かれているように、一定以上の容量/ダウンロード数を超えると制限がかかることもあるようです。

参考: https://www.dropbox.com/help/4204

100,000DLなどはヒットしたアプリだと軽く超える可能性があるので、作ってるものが広く使われ得るなら別の手段を検討するのが良いでしょう。

Google Analytics

3.アプリのログを取得することができる については、Google Analyticsを利用することでどのようにアプリが利用されているのかを知ることが出来ます。

例えばアプリの継続日数などはアプリを運営する上で最も重要な指標ですが、これを自前でダッシュボードを作って閲覧できる画面を作るというのは大きな手間です。Google Analyticsなら、下記の様に設定するだけでお手軽にこれを閲覧することが出来ます。
【Google Analytics入門】セグメントを使ってアプリの継続利用率を調べる方法

またActionやLabelを適切に設定しておくことで、チュートリアルを突破した、XXXのステージまでクリアした、のような情報を取得することが出来ます。今はもっと便利な方法があるのかもしれませんが、以前アプリを運用していたときはCategoryにアプリインストールした日付をCategoryとすることで、インストール日ごとにチュートリアル突破率などを分析していました。

イベント トラッキング - iOS SDK

新機能の効果を測定したり、チュートリアルの改善状況をチェックするために、特定の日にインストールしたユーザの挙動を分析してみる、というのはオススメです!これはコホート分析と呼ぶらしく、最近では公式のこの分析をする機能もGoogle Analyticsに用意されているようです。

Googleアナリティクスのコホート分析を使って分析してみました。

さらに、最近ではABテストまでサポートされているようです。

参考:
iOSアプリで、Google AnalyticsのABテスト機能を使う その1
iOSアプリで、Google AnalyticsのABテスト機能を使う その2

Google Analyticsのデメリット
複数の条件を絡めた分析を行おうとすると、どうしても煩雑になってしまう、というのはありました。例えばAという機能を初めて利用するとき、直前にどういったアクションをユーザーが行っている傾向があるのか?みたいなことは、上手くやれば集計できるのかもしれませんがGoogle Analyticsだと厳しいな、と感じました。

Firebase

実はまだ使ったことがないのですが、firebaseはリアルタイムなデータ同期を行うためのMBaaSです。5.ユーザー同士のコミュニケーション機能を作れるの様な機能で、さらにリアルタイム性があるもの、例えばチャット機能などを作ろうとした場合にフィットしそうなものです。リアルタイム通信やpollingする処理は自前で作ろうとするとなかなか大変なので、そういったアプリを作ろうとしてる場合は考慮に入れてよさそうです。

国内で有名な事例だと、WantedlyさんのSyncというアプリにも導入されているようで、商用プロダクトで利用するケースも徐々に増えてきているようです。

参考:
メッセージングアプリSync開発の舞台裏(iOS)
Firebaseを使ってみた

自前のサーバーを利用してサーバーサイドを実現する

前述の様にMBaaSを使うというのは非常に有効なのですが、上述するようにサービス毎にデメリットも存在します。またある程度のアクセスが想定される場合には意外とお金がかかったりすることもあるかと思います。企業ならまだしも、個人でまとまったお金を払うことは難しい、だが時間はある。その様な場合は、自前でサーバーを用意することを選択に入れてみるのもアリだと思っています。自分でサーバーを用意するメリット/デメリットは下記の様な感じだと思います。

自分でサーバーを用意するメリット
・MBaaSでは対応してないような機能も柔軟に作ることができる
・(上手く作ることが出来れば)大量のアクセスが来たときにはMBaaSよりも安く済む
自分でサーバーを用意するデメリット
・サーバーサイドのコードを書いたことがない場合、学習コストはかなりかかる
・万が一大量のアクセスが来た場合、スケールできる作りになっていないとレスポンスを返すことができず詰む可能性がある

これ以降は、自分が運営したサービスで自前でサーバーを用意して得た知見をまとめてみます。もちろん、環境構築から言語の説明までここでは書くことが出来ないので、実体験としてこれはやってみて良かったこと、などのTipsです。

VPS vs AWS

現状自前でサーバーを用意するとなると現状では、まぁこの2択になるかなと思っています。AWSのメリットとしてはインフラ周りの処理を自動化できることや、DynamoDB/Amazon RDS for Auroraなどのオートスケールがサポートされたデータ保存の仕組みがあることです。が、コスト的にはやはりVPSの方がどうしても安くなります。

参考: 【VPSか、AWSか、Herokuか】結局、最後はさくらVPS+Unicorn+Rails+Capistranoに行き着いた【構築スクリプト付き】

てかそもそも個人で作るアプリがオートスケール必要なレベルでアクセス来ていたら、それは恐らく個人開発のアプリという範疇を超えているのでは、という気がします。というわけで、さくらのVPSがコスパ的に一番良いと思います!なんと、月635円から利用することができます。
http://vps.sakura.ad.jp/specification/

さくらのVPSの設定周りについては、下記が非常に参考になりました。
さくらVPS&AWS&VULTR EC2/CentOS 6.5へのRailsサーバ構築手順![Ruby]

サーバーサイドの開発言語 / フレームワーク

サーバーサイドの開発を行うことが出来る言語には、PHP, Ruby, Python, Javaなど様々なものがあります。さらに言語ごとにフレームワークがいろいろあり、結局どれがいーんだよ!となりがちではあります。結論から言うと、まぁどれでも良いと思います。好みで!

で、いやそう申されましても、、、みたいな方に個人的にオススメなのは、ruby + sinatraの組み合わせです。何が良いかというと、必要最小限な機能しかないので覚えることがとにかく少ないという点です。下記のチュートリアルに従って実装すれば、Macをお使いなら3分くらいでブラウザにHello Worldと表示するところまではたどり着けると思います。

【初心者向け】RubyとSinatra、アンテナサイトの作り方

ただ、rubyだとRailsの方が機能は当然充実しているのでもしRails触ったことがある方ならRailsの方が最適だとは思います。自分も、今新しくアプリを開発してサーバーサイドの実装が必要になったら、Railsで作るかな、とは思ってます。

しかし、知識ゼロから最小限の動くものを作る、という点ではSinatraはなかなか良い選択だと思います。

ステージング環境

ステージング環境とは、本番とほぼ同じ状態で動作確認ができるサーバー環境のことです。アプリ開発とサーバーサイドの開発の違いとして、本番環境のマシンのコードが変われば、それがユーザーの手元のアプリの動作に即時に影響する、という点があります。

というわけで、まっとうに開発するなら、さくらVPSの635円のプランで良いのでもう一台VPSをレンタルして、一応ステージング環境は作っておくことをオススメします。

本番環境しかない状態でアプリを運営すると、例えば設定を変更したり、ソースコードを変更しても、それが正常に動作しているかどうか確認することにコストがかかってしまうためです。最悪、直接本番の設定ファイルを触ってしまったら全ユーザーのアプリが動作しなくなる、なんてことも考えられます。。

デプロイ

デプロイとは、開発完了してステージングで動作確認が完了したコードを本番環境に投入することです。真面目に環境を作るならばCapistranoなどの自動化ツールを利用するのが良いですが、正直個人のアプリでそこまでコストをかけたくない、という場合は本番のマシンにsshしてgit pullしちゃう、でも良い気もします。ちゃんとインフラやってる人には怒られそうですが、自分の場合は下記の様な雑なデプロイスクリプトを作ってステージング用のサーバーから本番環境にsshしてデプロイしていました。

deploy_script.sh
echo "cd /var/www/xxxxxxx;
      git pull --rebase;
      export RACK_ENV=production
      bundle install --path vendor/bundler;
      bundle exec rake db:migrate
      touch tmp/restart.txt;" | ssh username@host -i  key_path

キャッシュ戦略(クライアント編)

個人でアプリを作ってる場合は、やはりとにかく金をかけたくない、という思いを持って開発されてるケースが多いと思います。金はかけたくないけど、このアプリは大ヒットするでー!という心持ちで皆様開発されてることでしょう。大ヒットしてしまった場合に、問題となるのが負荷です。負荷。アプリエンジニアとしてお仕事してても、職場でサーバーサイドチームの机から「負荷が・・・」とか聞こえてきたりするアレですね。

負荷を裁くためには、金の力を使えばいろいろ選択肢があるのですが、金をかけないと決めてる場合には地道な対応がいろいろ必要となります。そのための戦略として有効なものの一つは、とにかくサーバーへのアクセスを減らす、ということです。そもそも、アクセスされなければ負荷もない!

というわけで必要なデータを取得してから、データをクライアント側に一定期間保存しておく、という処理は(金がないなら)入れておいた方がよいです。例えば、

  • マスタデータを取得してから24時間以内はアクセスしない
  • 更新頻度が低いと想定される情報は、1週間単位とかでキャッシュしてしまう
  • 不整合に備えてアプリ側の設定画面に、キャッシュ削除ボタンを用意しておく

などの実装が考えられます。

キャッシュ戦略(サーバー編)

おそらくサーバーサイドでアプリが大ヒットしてしまったときに一番苦しいのは、DBへの書き込み処理です。というかこれを分散させる必要が出たのなら、きっともはやそれは個人アプリというレベルではないのでこの記事の範疇外です。

しかし、それ以外のデータの読み込みについてはそれほどコストをかけずに負荷を軽減することができます。例えばデータの読み込みは直接データベースから情報を読むのではなく、サーバーのメモリ上にキャッシュしたデータを返すことで高速にアクセスを裁くことが可能になります。

このような仕組みは、RedisやMemcacheなどのミドルウェアを利用することで簡単に実装することができます。Memcacheの方がシンプルなインターフェイスなためとっつきやすいですが、Redisではデータの集合を操作しやすい(Sortなどがサポートされている)ので迷ったらとりあえずRedisのみ利用する、でもよいかもしれません。(自分で運営してたアプリでは当初memcacheのみ利用してましたが、最終的にsort処理などが必要な機能でredisを利用したため、結局両者を併用するハメになりました)

Redisの使い方
memcachedの基本

Health Check

個人で運用しているアプリの場合、障害が起きても担当者から電話がかかってくる、なんてことはないので残念ながら自分で障害を察知する必要があります。

大掛かりな仕組みを作る必要はないですが、1分に1回サイトにアクセスして、HTTPのステータスコードで200OKが返ってくることだけ確認、もし200以外ならばメールを送る、みたいな仕組みを作っておくと知らぬ間にアプリが動作しなくなってた、なんてことを防ぐことができます。

参考: Simple Script + Cron Job for Website Health Check + Apache Restart

自分の場合は、放置運用しているアプリのサーバーがさくらVPSの設定変更により強制再起動が走ったときにアプリが死んでてHealthCheckのメールが届いて気付いた、ということが一度ありました。。

amazonS3を利用したDBデータのバックアップ

個人運営アプリとはいえ、一応データベースのバックアップは取っておくことをオススメします。そこで便利なのがamazonS3です。

自分の場合は、下記のような簡易スクリプトを作って、1日に1回MySQLのdumpを1週間分までS3に上げるよう作っていました。(なぜ1週間分しか保存してないのか覚えてないけど、多分とにかく金を払いたくなかったからだと思います)

https://gist.github.com/kazu0620/2a7735d15ba74f3fca19

fluentdを用いたログ解析

さくらにさらに課金し、ログ用のサーバーを用意してfluentdを利用してユーザーのアクションは全てログサーバーに送信する、ということをしていました。

集めたログの解析にはいろいろな方法があると思うのですが、awkgrepsortwcなど素晴らしいソフトウェアがたくさんあるので、基本的にはこれらを使ってデータ分析を行ってました。ぶっちゃけBigQueryとかを併用して使えばよかったと今は後悔してるけどそれでも非常に細かい粒度でユーザーの行動を分析することは出来ていたのでまぁ良かったな、とは思っています。

結局そこまでは行いませんでしたが、nginxやapacheのログもfluentdに集約することができるので、ログ系のデータを一括で集約してクエリが発行できる環境で管理することが出来れば恐らく相当便利だとは思います。(個人アプリでどこまでやるのか、という話はありますが)

参考 Fluentdで始めるリアルタイムでのログ有効活用

まとめ

最後に、状況ごとにまとめてみると下記のような感じだと思います!

・金も時間もない
MBaaSを利用してアプリを作る(ただしアプリが大ヒットした場合には金を払う)
・時間はあるが、金がない
VPSで自前のサーバー環境を作ってみる。アプリが大ヒットしても大丈夫なようちゃんと設計は考えておく
・金はあるが時間がない
金で優秀なサーバーサイドエンジニアを雇えば良いのでは

金も時間もないが、大ヒットしても負荷に耐えられるアプリを作るには?

残念ながら銀の弾丸はないのですが、もしもあるとすればお金を生み出すようなアプリのビジネスモデルをちゃんと考えることじゃないでしょうか。

なんだかんだやはり重要なのは、アプリの価値をユーザーに届けること、もしもアプリが大ヒットするとか考えているのならしっかりビジネスモデルを考えること、だと思います。逆に、すごい負荷が来てるのにそれをカバーできるMBaaSの料金を払ったり、エンジニアを雇ったりするお金を集めることが出来ないのなら、それはアプリのビジネスモデルを何とかしないとどうしようもないというお話だと思います。

以上、個人でアプリ開発してサーバーサイドも作って得た知見でした!