OurPhotoの技術スタックを一挙公開！～改善活動の積み重ねでサービスの拡充を担う～

こんにちは！エンジニアの小西です。
出張撮影マッチングサービス「OurPhoto（アワーフォト）」で開発リーダーを担っています。

OurPhotoは、2020年11月にM&Aにてうるるグループにジョインしました。
グループジョイン後、OurPhoto開発チーム最初の1年間は、ソースコードの技術的負債の解消や、インフラ基盤・ ログ基盤の構築など、画面上では見えない部分の改善活動（システムリファクタリング）を中心に実施してきました。

そして今年は、OurPhotoサービス拡大のため、新規機能の追加や目に見える部分の改善活動をメインで行っています。

今回は、そんなOurPhotoシステムの裏側をお話ししたいと思います。

## OurPhotoとは
写真を撮ってほしい個人と写真を撮りたいフォトグラファーをつなげるマッチングサービスです。

https://our-photo.co/

サービス特性として、以下があります。
- 大量の画像データを扱う（保存 & 表示）
- 画像データは、フォトグラファーが撮影した品質を保った状態でユーザに届ける必要がある
- 写真撮影需要・イベントの多い時期には、多数のユーザがサービスを利用する。（例: 七五三シーズン, 卒業シーズンなど）

OurPhotoのシステムでは、上記特性を解決するサービスアーキテクチャである必要があります。
こちらを念頭に置きつつ、アプリケーション構成・インフラ構成を説明していきます。

## アプリケーション関連
![our-photo_infra(インフラ図)-外部記事用(アプリ構成) (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351743/dbe019a5-d6cc-3af2-a238-ccd1763277d3.jpeg)

### バックエンド使用技術
開発言語は主にPHPを用いており、フレームワークはLaravelを使用しています。
また、サーバレスアーキテクチャ部分の実装で一部Go言語を用いています。

PHPUnitを用いて単体テストコードを実装しており、アプリケーション全体のテストカバレッジの可視化と改善を行っています。グループジョイン時点ではテストコードが存在していなかったので、1年かけて全てのコードに対してテストコードを実装。現在では新規コード追加 + テストコード実装はセットになっています。

その他、PhpMetrics, CodeClimateなどのツールを用いてソースコードの静的解析を実施し、技術的負債の可視化, 継続的観測にも取り組んでいます。

### フロントエンド使用技術
フロントエンドの大半は、Laravelのbladeテンプレートを用いて構成されています。
一部画面（チャット、 画像アップロードなど、非同期通信が多く使われる画面）では、Vue.js2系を用いて実装されています。
フロントエンドテストについては、Cypress用いてE2Eテストを自動実施しています。
E2EテストはCircleCI上で自動で実行され、コードレビューをするエンジニアが画面上の差分を確認する形式を取っています。

現在、フロントエンド実装をVue.jsで記述するためのリファクタリングを実施中であり、Vue.js3系、TypeScriptの導入を進めており、同時にJestを用いた自動テストの導入にもチャレンジしているところです。

## インフラ関連
![our-photo_infra(インフラ図)-外部記事用 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351743/0fb84216-3a4f-4f1a-f80a-75341c94bd10.jpeg)

### 前提
実はOurPhotoのインフラ基盤は、2021年8月までAzureにて構成・稼働していました。
さまざまな理由により、インフラ基盤をAWSへフルリプレイスし、現在では全てのアプリケーションがAWS上で動いています。
詳細は割愛しますが、リプレイスにおける重要ポイントは以下でした。

- セキュリティ課題の解消
- 冗長化と可用性を高め、サービス拡大に備える
- 監視基盤を整え、サービスの信頼性を高める

これらを達成するためのアーキテクチャを目指し、リプレイスを実施しました。
リプレイスにおける大きな変化は

- サーバーのコンテナ化
- デプロイの自動化
- webサーバー、DBサーバーのオートスケールによる負荷軽減
- CloudwatchやDatadogを用いた監視基盤の整備

あたりです。

### アプリケーション系リソース
コンテナをベースとしたアーキテクチャとなっています。
アプリケーション用、バッチ(定時処理)用のコンテナがありますが、いずれにおいてもコントロールプレーンとしてはAmazon ECS、データプレーンとしてFargateを用いています。

一部機能（フォトグラファが写真を納品する部分）については、lambdaを用いています。S3に画像がアップロードされたことをフックとしてlambdaを起動させ、画像リサイズ・S3に再アップ という動きを担っています。
写真納品部分をサーバレスアーキテクチャ構成にして、アプリケーション本体と切り離すことにより、画像大量納品時の負荷軽減・速度上のボトルネック回避などの効果を狙っています。

### データ永続化層
データ永続化層として、Redis(ElastiCache), Auroraを用いています。Auroraについてはリードレプリカを使用しており、読み込み負荷向上時には自動でスケールするようにしています。（これは、ECSも同様です）自動スケール機構の実装により、繁忙期の急激なアクセス数増加・負荷増大に備えています。

また、lambdaのDB向け先もAuroraになっていますが、lambda → RDSの同時接続数増加問題に対処するため、lambda、Auroraの間にはRDS Proxyを配置して、DB接続コネクションをプールし、節約するようにしています。

### 画像周りの扱い
画像については、S3に保持しています。大量に存在しているため、一定期間が経過した画像についてはS3 Glacierにアーカイブさせ、コスト最適化を図っています。
画像表示についてはCloudFrontを用いることで、キャッシュによる高速配信を狙っています。

### 監視
監視ツールとして、DataDog、Bugsnag、Uptime Robotなどを用いています。

DataDogは、CPU・メモリだけでなく、APMによって内部のトレースを実施しています。これによって、スロークエリとなっている箇所を特定し、パフォーマンスチューニング実施などに役立てています。
実際に、画面描画まで平均15秒ほどかかっていた箇所を、1秒ほどに短縮させたと言う成果も出せました。

アプリケーションで発生したバグの通知・管理にはBugsnagを用いています。
Bugsnagではバグ発生時の対応も素早くこなせるようになったり、日々のバグ数を計測しシステムの信頼性の見える化などに役立てています。

アプリケーションの死活監視にはUptime Robotを用いています。

### 構成管理
インフラ系リソースの大部分は、terraformにてコード化して管理しています。
一部リソース（サーバレス周り）については、AWS SAMを用いて構成管理しています。
いずれにせよ、ほとんどのリソースについてコードベースでの構成管理を実施しています。

### CI/CD
CI/CDツールとしては、CircleCI、AWS Codeシリーズ（CodeCommit, CodeBuild, CodeDeploy, CodePipeline）を用いています。

CI（継続的インテグレーション）については、GithubへのpushをトリガーにCircleCIが起動し、PHPUnit自動テストが走ります。こちらが全通過しないとマージ可能にならないようにすることで、大元ブランチにpushされるソースコードの品質を担保しています。
CD（継続的デプロイ）については、AWS Codeシリーズを用いて実施しています。

またインフラ側についてもCI/CDを実施しており、こちらはCircleCIを用いて、plan, applyまで自動化しています。
terraformによる誤変更が起きてしまうと、インフラが停止してしまいかねないため、terraform planの内容をCircleCIにて確認し、手動で承認をする仕組みを導入しています。
承認をするとapplyが走るようになっています。

## 開発体制・開発の進め方など
ソースコードの管理にはGithubを用いています。
また、エンジニアが書いたPRに対しコードレビューをルールづけており、コードレビューとCIが通って初めてリリースフローに乗ります。

OurPhotoではスクラム開発を導入しており、1週間のスプリントで開発サイクルを回しています。
リリースも毎週リリースしており、リリースできるものはリリースするという流れで、継続的にスピーディなサービス改善につなげています。

## まとめ
OurPhotoのシステム裏側について、説明させていただきました。

1年間のシステム改善活動で、ソースコード・アーキテクチャを整理・再構築し、今後のサービス拡大のための基盤を構築してきました。

今後はサービス拡大に向け積極的に新規機能開発を加速させていくため、技術的なチャレンジを重ねていきたいと思います！