はじめまして。株式会社トルテでサーバーサイドを担当している中川です。 レディーファーストの恋アプリTorteを開発しています。

恋アプリTorte

https://sweet-torte.com/

今年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のマネージドサービスを活用しているプロダクトが周りに多く、知見が活かせるということで、開発スピードを重視した結果となりました。

アーキテクチャ

全体

次の図は、ざっくりした全体の俯瞰図になります。 Torte All

基本的に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のオートスケールの設定についてですが、CPUReservationMemoryReservationというECSにのみ存在するメトリクスを使うことで、1つのClusterに複数Serviceが相乗りする場合でもシンプルかつ柔軟にスケールさせることが出来ます。

Amazon ECS のメトリクスとディメンション – Amazon CloudWatch

Application

Amazon ECSの部分を詳細に見ていきます。 Torte Application

ここでは本番環境(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

アプリケーションのデプロイについてです。 Torte Deploy Application

何パターンか検討した結果、最もシンプルで素早く実現できるecs-deploy (https://github.com/silinternational/ecs-deploy)を使う方法を採用し、ユースケースに合わせてecs-deployに手を加えています。masterにマージされるとstg環境、git tagを切るとprd環境に、CircleCI経由でECSに対してローリングアップデートが実行されます。

Website

コーポレートサイト、サービスの公式サイトの管理も自動化しています。 Torte Deploy Website

アプリケーション同様、masterにマージするだけで確認環境(stg)が更新されるので、手軽で確認しやすいとデザイナーの方に喜ばれています。

Log

紆余曲折あったログ周りの構成です。 Torte Log

深掘りするとログ周りの話だけで1つ記事が書けそうなボリュームがあるので、今回は割愛します。

当初はCloudWatch Logsを使う予定でいました。Docker logging driverにawslogsを指定することで、標準出力、標準エラー出力に吐き出すだけで導入できて大変便利なのですが、ログが欠損しない事といった信頼性の面に於いて懸念があり、アプリケーションから直接Kinesisに投げてバッファリングする形に落ち着きました。

Torteでは4つの種類のログを扱っています。

  • アクセスログ
  • アプリケーションログ(エラーログ)
  • KPIログ
  • 投稿監視ログ

前者2つはElasticsearch Serviceに転送し、Kibanaで可視化しています。 後者2つについては基盤システムに送る必要があり、Lambdaからfluent-logger-pythonを使って転送しています。

さいごに

新規サービスTorteのアーキテクチャについてご紹介いたしました。立ち上げに携わるのは初めてで、一から技術選定、設計、実装に携わる貴重な経験でした。

技術は日々進歩していくので、エンジニアとして常に情報をキャッチアップし、時には新しい技術に挑戦することで、ユースケースに合ったコストパフォーマンスの良い手段を選択していかなければならないと思います。

トルテはIT技術で、幸せな出会いをサポートしていきます。

2016年度新卒入社のサーバーサイドエンジニアです。GoとJavaScriptを喋ります。趣味は旅行とアニメとお菓子作り。