こんにちは。株式会社High LinkのCTOの野川賢二郎 (@nogaken)です。
この記事では、新しくハイリンクにジョインした方や、これからするかもしれない候補者を主な対象に、カラリアを支える技術スタックを紹介しそれぞれの技術を使用するに至った経緯などを簡単に紹介していきます。
サービス概要と全体の構成について
ハイリンクでは「COLORIA (カラリア)」という香り商品のECサービスを運営しています。中でも「カラリア 香り定期便」は月額制のECサービスで、毎月ユーザが選んだ香り商品をお届けすることによって従来購入障壁が高かった香水をはじめとする香り商品を手軽に試し、楽しむことができます。
サービスとしてデータを用いて香り商品との出会いをサポートすることに力をいれており、ユーザのレビューデータを活用して香りの好みを可視化するフレグランスプロフィールや、サービスからの質問を元に好みの香りの種類とおすすめ香水を提示する香水診断、注文履歴から次の注文をおすすめするレコメンド機能など、サービスに蓄積されたデータを活用した各種機能を提供しています。
カラリアを支えるシステムは大きく分けて2つのシステムに分けられています。
- カラリア本体
- ECシステム
- 基幹業務システム
- 管理画面
- Data API
1のカラリア本体は、ECシステム、基幹業務システム、管理画面で構成されています。基幹業務システムは在庫管理と発送管理を主に担うコンポーネントで、現状はECシステムと密結合しています。現在、ECと基幹業務のコンポーネントのモジュラーモノリス化を進めており、その取り組みは別記事で紹介できればと思います。
2のData APIでは、香水診断やレコメンドといったデータを活用したAPIを提供しています。カラリアではサブスクリプションサービスで収集された購入履歴やレビューといったデータを活用した機能の開発に力を入れており、それらのロジックを提供するコンポーネントを切り出しています。
全体像を図にあらわしたものが以下です。
以下では、カラリア本体、Data APIそれぞれについて使用されている技術を紹介していきます。
カラリア本体
Webバックエンド
カラリア本体のバックエンドにはRuby on Railsを使用しています。バージョンは6.2です。定期的にアップグレードをしており、バージョン7へのアップグレードも計画中です。
Ruby on Railsは、カラリア開発初期 (2018年)に現CPOの百瀬が開発経験があり、現CTOの野川も触れた経験があったため、もっとも速くリリースまで持っていくために選定しました。時の流れとともに徐々にバックエンドのフレームワークの主流から外れていっていますが、ActiveRecordの存在により高速にAPIを新規開発できる点は優れていますし、採用という面においても経験者が多いため弊社のようなシリーズA, Bのまだまだ小規模なスタートアップには適していると思っています。
Webフロントエンド
フロントエンドはNext.js, TypeScript, Tailwindcssの構成となっています。2021年まではフロントエンドもRailsでしたが、フロントエンドの開発体験を向上させ、結果的にユーザー体験向上の速度を高めることを目的に、Railsと密結合していたフロントエンドをNext.jsに移行しています。
WebpackerやSimpackerなどでモダンフロントエンドをRailsアプリに組み込む方法はありますが、フロントエンドはNext.js、バックエンドはRuby on Railsと明確に責務を分離し疎にする方向を選択しました。これにより、フロントエンドエンジニアがRails側のパイプラインを意識する必要がなくなり、オンボーディングや採用面でも良かったと考えています。
フロントエンドのNext.jsへの移行完了度は80%程度で2022年の秋ごろには完了予定です。
フロントエンドのフレームワークにNext.jsを採用した理由は主に二点あります。一つ目は、Next.jsのZero Configの恩恵を受けたかったためです。フロントエンドリニューアルを決定したタイミングではフロントエンドの技術スタックに慣れ親しんだメンバーがいなかったため、複雑な設定を回避したいという気持ちがありました。二つ目は、SSRを手軽に行える点です。サービスの性質上、OGPやSEOの観点でSSRが不可欠だったため、手軽にページごとにSSRを実装できる機能は魅力的でした。
また、型により開発体験を向上させ頑健なコードを記述するためにTypeScriptを採用しています。TypeScriptの設定は最初、Next.jsのデフォルトの設定となっており、strict: trueとなっていないのが現在の課題です。noImplicityAnyは現在trueになっていますが、strictNullChecksはfalseとなっており、現在設定変更を計画しています。これにより、よりバグの少ないコードを記述できるようになると考えています。
インフラ
カラリア本体のインフラにはAWSを利用しています。
アプリケーションのホスティングはFargateを利用しています。
2021年まではECS on EC2で稼働していましたが、管理コストを低減するためにECS on Fargateへ移行しました。EC2使用時はインスタンスに不要なファイルが蓄積されたことが原因による障害などが生じたことがありましたが、Fargateへの移行後は大きな問題が生じておらず、移行コストに見合った管理コスト削減が行えたと思います。
また、ECS on FargateはEC2インスタンスを管理する必要がなくオートスケールを簡単に設定できるため、サービスのTV露出があり大量アクセスが想定された際にスムーズに対応することができました。
非同期処理基盤
非同期処理のためのタスクキューイングにSQSを利用しています。アプリケーション側ではSQSと連動したActive Job WorkerであるShoryuken を利用しています。現在はメールの配信のみが非同期として処理されており、それ以外の処理は同期処理となっています。
インフラの管理
インフラの設定はTerraformによってコードで管理されています。これによりインフラの構成がアプリケーションコードと同じようにコードレビューを行えるためより管理がしやすくなりました。terraform planやapplyはGithub Actions上で実行されるようになっており、プルリクエストに対してterraform planの結果がコメントされ、マージするとapplyされるようになっています。
Data API
Webバックエンド
Data API用のWebフレームワークにはPythonのFastAPIを使用しています。
元々はFlaskをベースに開発をしていたのですが、AWS → GCPへの機械学習基盤移行のタイミングでFastAPIに切り替えました。
その理由として、スキーマ駆動開発がしやすく型安全な開発が容易な点、SwaggerUIへのドキュメント自動生成をサポートしている点、Flaskよりも高速な点が挙げられます。
Pythonを利用しているのはいわずもがな、機械学習でのデファクトスタンダードであるからです。
ハイリンクでは、機械学習エンジニアが機械学習のAPIのホスティングも担います。これにより機能リリースまでに必要な余計なコミュニケーションが少なく、素早く新しい機能を追加できています。
インフラ
データ系のインフラにはGCPを使用しています。
もともとAWS上でカラリアが動いていたところに新たにData APIのインフラにGCPを選定したのは、機械学習という文脈ではAmazonよりGoogleのほうが優位性があり、Googleの肩に乗るほうが良いと判断したためです。また、すでに導入を決定したBigQueryとの連携という点においても同じGCPのほうが分があるというのもあります。
アプリケーションのホスティングにはCloud Runを利用しています。サーバーレスでフルマネージドであり、簡単にAPIのデプロイができるため選定しました。
また、Cloud Workflowをベースに、Cloud Functions, Cloud Run, Cloud Scheduler を組み合わせてML (Machine Learning)パイプラインを構築し、前処理 → モデル構築 → サービングという一連のフローを自動化しています。これにより日々増えていくデータを反映した機械学習サービスを提供することが可能となっています。
AWSとGCPの併用は、既存のAWSで動いているリソースをそのままに、GCPが強みとするデータ関連のサービスの恩恵を得られるというメリットはあるものの、学習コスト・管理コストが高くなったり各IaaSの知識が深化しにくいというデメリットはあると感じています。そのためアプリケーションのホスティングはAWSに集約させデータパイプラインのみをGCPに置くかどうかなど、より組織フェーズにあった形にアップデートしていくことを検討しています。
その他
CI/CD
CI / CDにはGithub Actionsを利用しています。2021年まではCircleCIを利用していましたが、コスト面と、ディレクトリごとのAction制御が非常に便利なためGithub Actionsに移行しました。
移行したところ、常日頃触るGithub上でCI/CDが完結するシームレスな点が心地よく、気に入っています。
カラリア本体を例に挙げると、フロントエンドはESLintとJestが、バックエンドはRspecが各ブランチにpushする度に実行されるようになっており、アプリケーションのデグレーションに気づけるようになっています。デプロイについては、masterブランチでバージョンタグを発行するとリリースされるようになっており、素早く変更をリリースできるようになっています。
監視
エラー監視にSentryを、アプリケーションとインフラ監視にDatadogを利用しています。
2021年まではSentryのみを利用しており、その他のモニタリングにはCloudwatchを利用していましたが、アプリケーションのパフォーマンス改善をする上ではCloudwatchでは不十分なためAPM (Application Performance Monitoring)とインフラ監視両方を行えるDatadogを導入しました。
NewRelicも候補として上がりましたが、DatadogのほうがUIが優れており、機能同士の連携がより充実している印象を受けたためDatadogを選定しました。
DatadogでもSentryが担うエラー監視をすることもできますが、Sentryはエラー監視に特化しているだけあって使い勝手がよいため現状は両方を利用しています。
おわりに
カラリアで使っている技術やサービスの紹介を行いました。
実際にはこれら以外にも細かいところで他のサービスを使用していたりしますが、それは詳細記事として紹介していければと思います。
ハイリンクではカラリアのユーザー体験向上を高速にかつ安定的に実現するために技術スタックのアップデートに取り組んでおり、ともにサービス改善に取り組む仲間を募集しております。
副業でのコミットや、気軽にお話をするだけでも歓迎ですので、興味のある方はぜひ下記リンクからご応募ください。