アーキテクトのItoです。動画を撮るのが趣味ですが、最近はこの本を買って、カラーグレーディングの勉強をしています。とても良い本です。
さて、今回お話するのはバックエンドにあるフロントエンドについて。
以下はほぼ実際にカメリオで運用しているバックエンド構成です。
図中のサーバーというものはいわゆるHTTPベースのサーバーアプリで、ここでは緑をNode.js, グレーをPython, C++で実装しています。小さいサーバーがたくさんあります。主にクライアント〜フロントエンドAPIだけの構成図で、記事クローラーや各種管理画面などは図にはありませんが存在します。
まずフロントエンドにELB(AWSを使用)とNginxを置き、後ろに
NodeベースのフロントエンドAPIサーバーを置きます。
ここはNode.jsで作られたアプリをサービスするごく一般的な方法です。
エンドポイント(api.kamel.io)はJSONを使うHTTPのAPIで、iOS, Android, ブラウザ版(以下クライアント)から使われます。
純粋なRestfulではありませんが、画面ごと1リクエストとなるように設計しています。
外部(クライアント)から直接アクセスできるのはNginxを通過した、フロントエンドAPIサーバーだけで、バックエンドのサービス群はフロントエンドのAPIが使うことになります。
フロントエンドAPIは後ろのバックエンドサービス群と通信します。この間はHTTPのAPI(JSON)またはJSON RPCを使って通信します。
永続化するデータはデータベースにすべて置くことになりますが、ほぼすべてのサーバーがデータベースにアクセスします。(AWSではWebサーバーを置くインスタンスはリリースやデプロイメントごとに、古いものは破棄するように使うことができます。そのため永続化するデータはすべてデータベース上に置くことになります。)
フロントエンドAPIサーバー
カメリオの場合、特にクライアントからアクセスされるAPIの種類はフォローなどのユーザーの情報に関するもの、リコメンド、記事の検索など、いくつかのパターンに分かれます。
そのため、2つのフロントエンドAPIサーバーに分かれていて、それぞれ用途別に違う処理をします。実装はNode.jsです。
ユーザーデータ系APIサーバー A1: 各種ログインやユーザーのテーマフォロー、リコメンド系のデータ、行動のデータを扱い、セッションもここで解決します。やる仕事はシンプルで、バリデーションを含めたDBへの格納と取り出しです。
それ以外のことは特にせず、自分でできないことは、バックエンドのサーバーにプロキシする、バックエンドのサーバーのいくつかのリクエストの結果をまとめてクライアントに返します。
たとえば、おすすめ記事をリコメンドすることはCPU処理が必要で、1処理に時間もかかります。Node.jsで行うこともあまり適していません。
おすすめ記事のバックエンドサーバー B1として置き、実際の処理はそのサーバーが行います。
記事系APIサーバー A2: 記事と検索です。あるテーマの記事をユーザーごとに出したり、テーマのサジェストと検索を実行して、結果をクライアント返します。記事の検索は日々進化するところなので、クライアント向けの処理(リクエストを整形したり、DBとJoinしたり)はNodeがやって、肝心の検索は後ろのバックエンドサービスが行います。
Node.jsは小さいサーバーを素早く書けるため、フロントエンドAPIに使うことは選択肢として適しています。逆に小さいサーバーであるので何でもよく、たとえばJavaでもGoでもいいと思います。(実装する人が慣れているものなら)
疎結合によるメリット
全体が疎結合なため、サーバーごとにテストしたり、スケールしたり、実装したりすることが容易になっています。
また、何か新しいプロジェクトやサービスを追加したり実験したりしたいときも、今までに作ったサーバーを組み合わせることができるので、検証や実装の短縮にもなります。
小さいサーバーはホスト名とポート名さえ区別できれば良いので、どのインスタンスにあってもかまいません。
作る人でサーバーを分けることもできます。テストもサーバー単位でもできます。
マネジメントを考える場合、小さいサーバーとのインタフェースはHTTP APIのリクエストのみなので、
最初にここの仕様を定義して、実装とテストを実装する人に任せます。
実装が完了したら、完成したものが定義通り十分なパフォーマンスで動作しているかを検証します。
運用と管理
小さいAPIサーバーをいくつも置くため、1つのアプリサーバーを置く場合に比べて、障害やパフォーマンスをリアルタイムに計測する必要があります。各サーバーをデーモン化して、落ちたときの自動再起動、一定時間ごとに各サーバーのAPIにアクセスをして、レスポンスが遅かったり、エラーになった場合、アラートを上げるようにしています。
まとめ
変化が速く、素早く作らなければならないスタートアップにとって、サービスのアーキテクチャは大きな課題です。
最初は小さいプロトタイプを作って、ベータ版、そして正式リリース、ユーザー数増というなかで、スケールしていかなければなりません。1週間単位で機能も増えたり減ったりします。
特にカメリオのような情報を検索したり、リコメンドしたりするサービスは
バックエンドはいくらでも大きくなることがありますし、いつでも拡張したり変更したりすることがあります。
現在ユーザーアカウント数は約10万です。
これがどの場合でも使えて、かつ正解というわけではありませんが、ベータを経て、サービス開始時から運用してきて実際にうまくいっている1つのケースです。