はじめまして。株式会社トルテでサーバーサイドを担当している中川です。 レディーファーストの恋アプリTorteを開発しています。
今年8月にリリースしたTorteのサーバーサイドのアーキテクチャについて、技術選定の理由やTipsと共にご紹介いたします。
技術選定
Go + Docker
以前担当していたサービスで急激な高負荷に耐えられないことが多々あり、EC2を使ったスケールに限界を感じていました。Docker Containerを使ったオートスケールやデプロイに関心があり、今回はDockerと、シングルバイナリで稼働して相性が良いGo言語を採用する運びとなりました。サイバーエージェントグループでの採用事例もあり、新規ならDocker + Goという流れがあったので、採用にあたって特に障壁はありませんでした。
Cloud Service
クラウドはGCPとAWSを検討しました。GCPにはGoogle Container Engine (GKE)、AWSにはEC2 Container Service (ECS)があるので、どちらでもマネージドのDocker Containerサービスが利用できます。結果的には、AWSを採用しました。個人的にはGCPを使ってみたかったのですが、AuroraやS3、ElastiCache、Kinesis、LambdaといったAWSのマネージドサービスを活用しているプロダクトが周りに多く、知見が活かせるということで、開発スピードを重視した結果となりました。
アーキテクチャ
全体
次の図は、ざっくりした全体の俯瞰図になります。
基本的にAWSのサービスを利用していますが、一部外部のサービスを利用しています。認証、プッシュ通知、リアルタイムDBにFirebase、モニタリングにDatadogを採用しています。
AWS上のリソースは基本的に全てTerraformで管理されていますが、Route 53だけはRoadworkerで管理しています。Terraformと異なりRoadworkerではstate fileを持たず、常に現状との差分を取るのでDNSレコードを管理する上では使いやすいという理由があります。
Static Files
静的ファイルはGit管理の上で、S3に同期されています。前段に画像変換プロキシ(Image Proxy)を挟むことで縮小、形式の変換、切り抜きの処理とキャッシュを行っています。
Datastore
メインとしてAmazon Aurora、KVSとしてElastiCache (Redis)を採用しています。 マッチングサービスに欠かせない、ユーザー検索のロジックの実現にはElasticsearchを用いています。詳しくは以下の資料を参照してください。
Auto Scaling
ECS Cluster, Serviceそれぞれにオートスケールを設定し、負荷に応じてServiceがスケール(Taskが増減)、残リソースに応じてClusterがスケール(Instanceが増減)します。
ECS Clusterのオートスケールの設定についてですが、CPUReservation
とMemoryReservation
というECSにのみ存在するメトリクスを使うことで、1つのClusterに複数Serviceが相乗りする場合でもシンプルかつ柔軟にスケールさせることが出来ます。
Amazon ECS のメトリクスとディメンション – Amazon CloudWatch
Application
Amazon ECSの部分を詳細に見ていきます。
ここでは本番環境(prd)のみ記載していますが、環境毎に1つずつECS Clusterが存在します。Task毎にIAM Roleで権限を分けることができるので、1つのClusterに複数Serviceを混在させることが可能です。
大きく分けてAPI, Admin, Batchの3つのシステムが稼働しています。末尾がdd_agent
のものは、Datadogにメトリクスを送るためのECS Serviceになります。api, admin-web, admin-apiはそれぞれECS Serviceとして登録されオートスケールが設定されています。サービスディスカバリにはALBが使われ、実際にServiceを構成するTaskがClusterを構成するどのInstanceにデプロイされても問題ない仕組みになっています。
API
サービスの根幹となる、ネイティブアプリからアクセスされるAPIです。 100% Goで実装されています。go-bindata(github.com/jteeuwen/go-bindata)を使うことでassetを含めてシングルバイナリになっています。Docker Imageにはalpineを採用しました。
Goでの実装に関するTipsについては以下の資料を参照してください。
Admin
管理画面です。こちらにはFrontendがありadmin-on-rest (https://github.com/marmelab/admin-on-rest)を採用しています。
AdminのAPIは、基盤システムからのリクエストの受け口としても機能しています。
Batch
定期実行処理と手動オペレーション(DBマイグレーションなど)を実行するためのシステムで、必要な時だけECS Taskが起動します。
定期的な起動はCloudWatch Eventsがトリガーとなっています。
Amazon ECS タスクのスケジューリング – Amazon EC2 Container Service
デプロイ
Application
アプリケーションのデプロイについてです。
何パターンか検討した結果、最もシンプルで素早く実現できるecs-deploy (https://github.com/silinternational/ecs-deploy)を使う方法を採用し、ユースケースに合わせてecs-deployに手を加えています。masterにマージされるとstg環境、git tagを切るとprd環境に、CircleCI経由でECSに対してローリングアップデートが実行されます。
Website
コーポレートサイト、サービスの公式サイトの管理も自動化しています。
アプリケーション同様、masterにマージするだけで確認環境(stg)が更新されるので、手軽で確認しやすいとデザイナーの方に喜ばれています。
Log
紆余曲折あったログ周りの構成です。
深掘りするとログ周りの話だけで1つ記事が書けそうなボリュームがあるので、今回は割愛します。
当初はCloudWatch Logsを使う予定でいました。Docker logging driverにawslogsを指定することで、標準出力、標準エラー出力に吐き出すだけで導入できて大変便利なのですが、ログが欠損しない事といった信頼性の面に於いて懸念があり、アプリケーションから直接Kinesisに投げてバッファリングする形に落ち着きました。
Torteでは4つの種類のログを扱っています。
- アクセスログ
- アプリケーションログ(エラーログ)
- KPIログ
- 投稿監視ログ
前者2つはElasticsearch Serviceに転送し、Kibanaで可視化しています。 後者2つについては基盤システムに送る必要があり、Lambdaからfluent-logger-pythonを使って転送しています。
さいごに
新規サービスTorteのアーキテクチャについてご紹介いたしました。立ち上げに携わるのは初めてで、一から技術選定、設計、実装に携わる貴重な経験でした。
技術は日々進歩していくので、エンジニアとして常に情報をキャッチアップし、時には新しい技術に挑戦することで、ユースケースに合ったコストパフォーマンスの良い手段を選択していかなければならないと思います。
トルテはIT技術で、幸せな出会いをサポートしていきます。