バックエンドはScala!インフィード広告プロダクトCirquaのバックエンド技術構成を紹介します

マーベリック技術広報のリチャード伊真岡です。

今回は弊社のインフィード広告プロダクトCirquaの技術構成及び技術的課題の一部を紹介したいと思います。CirquaのバックエンドはScala、フロントエンドはTypeScriptで書かれており、今回の記事ではバックエンドの紹介をします。

採用技術: Scala, Finagle, PlayFramework, ScalikeJDBC, Amazon RDS(MariaDB), Amazon ElastiCache(Redis), Fluentd, Amazon S3, Amazon Athena 等

Cirquaの仕組み紹介

Cirquaはインフィード広告と呼ばれる種類の広告を主に扱うプロダクトです。

f:id:maverick-techblog:20190801145339p:plain

インフィード広告とはSNSのニュースフィードに代表されるようなタイムライン状に表示されるコンテンツの中に表示される広告を指していて、「フィード」の「中」に表示されるので「インフィード広告」と呼ばれています。

技術構成の紹介の前に、まずCirquaの仕組みを簡単に紹介したいと思います。以下では訪問者がCirquaを導入しているメディアのWebサイトを閲覧したときの動作を簡略化して説明します。

f:id:maverick-techblog:20190801145324p:plain

訪問者がWebページを閲覧すると、ページのHTMLに埋め込まれたCirquaのScriptタグが読み込まれます。そのScriptタグによってマーベリック側のネットワークにある広告配信サーバから広告を取得しWebページ内にインフィード広告が表示されます。

f:id:maverick-techblog:20190801145345p:plain

インフィード広告が表示された時点で訪問者が広告を表示したことがカウントされ、それをアドテクの世界では「インプレッション」とよんで計測しています。インプレッションの発生はトラッキングサーバに送信され、更に訪問者がその広告をクリックして広告主のウェブサイトへ遷移した場合その「クリック」をトラッキングサーバに送信しそれも計測しています。

またトラッキングサーバ側は集計処理も行うので以下のデータ集計用のフローにもつながっています。 計測、集計したデータは機械学習チームにも渡され、広告配信の配信ロジックに利用されます。

f:id:maverick-techblog:20190801145343p:plain

Cirquaのバックエンドで採用している技術スタックを以下のように図示してみました。Webページから送信されたインプレッションとクリックのデータはfluentdを介してAmazon S3に送られ、バッチ処理が定期的に走ってAmazon Athenaを用いて集計しています。Amazon Athenaを使うとS3にため込むデータの形式さえ整えれば集計処理が手軽にできるので運用はとても楽です。

Cirquaバックエンドの技術スタックを以下のように図示してみました。

f:id:maverick-techblog:20190801145352p:plain

広告配信サーバはScalaで書かれており、非同期処理部分はFinagleを用いて実装しています。HTTPのRequest/Responseのパラダイムに従って素直に非同期処理が書ける点がCirquaチームがFinagleに感じる魅力です。トラッキングサーバはPlayFrameworkを使っています。このFinagleとPlayFrameworkの使い分けはチームの両フレームワークに対する慣れや過去のプロダクト開発における知見の積み重ねなどから総合的に判断して使い分けをしています。バックエンドのデータベースはRDS(MariaDB)を使っていてScala側からはScalikeJDBCを使って接続しています。ScalikeJDBCはSQLを素直に書けるところが使いやすいライブラリだと感じています。

バッチ処理については先進的な試みとして一部でScala ZIOを取り入れています。Scala ZIOは関数型を活かしつつもオブジェクト志向プログラマにも馴染みがあるDependency Injectionを取り入れており新たに学ぶ概念が少なくわかりやすいとされています。非同期処理がきれいに書けるところがとても良いと感じています。バッチ処理は広告配信サーバとトラッキングサーバ本体とは切り離されているのでScala ZIOの導入がしやすく、まずはバッチ処理から取り入れてみることにしました。

開発チームの構成

Cirqua開発チームの構成は:

  • バックエンドエンジニア2人
  • フロントエンドエンジニア3人
  • プロダクトオーナー1人

となっており、これ以外にインフラエンジニアとCirquaを含む複数プロダクトのサーバーやネットワークを管理し、Quality Assuranceチームが同じように複数プロダクトを担当しています。

Ciruquaチームでは毎週のリリースをdevelop環境は木曜、production環境は月曜日にリリースを行っています。 develop環境のリリース後はQuality Assuranceチームを交え全員で画面を触り、新機能のチェックを行います。 こうすることで常にチーム全員がプロダクトの新機能、いつどの機能が入ったかなどを把握できる状況を作っています。

リリースはslack botから実行できるよう自動化されています。少人数チームではContinuous Deliveryの仕組みは必須ですね。

今取り組んでいる技術的課題

現在CirquaのインフラについてはAmazon EC2上でそのままプロセスを走らせる形からKubernetesを使った運用に移せないか検証を行っている最中です。もちろん導入が上手くいけばKubernetesエコシステムを活かしたインフラ運用、そしてアプリケーションエンジニアがインフラ運用の一部を担当できるというメリットを狙ってのものですが、なによりKubernetesを触るのはエンジニアとして楽しいですよね!Kubernetesに伴う負担を可能な限り軽減しつつ、楽しさを存分に活かせる導入方法を現在模索中です。

さらにCirquaシステムは一部リファクタリングを行っており、Domain Driven Design的な設計手法を取り入れてアプリケーションのコア部分を書き直しています。scala言語の表現力の高さを活かし、コアドメインを宣言的かつ表現力豊かに再定義することができています。チームメンバは社内で開催されているDomain Driven Design読書会にも参加し、Domain Driven Designに対する理解を深める努力を行っています。