Data-Driven A/B Testing を高速に回すための DevOps 基盤

はじめに

みなさん、こんにちは。 データエンジニアリングG CET チームの菅沼です。
普段は、分析基盤の開発や機械学習モデリングなどを担当しています。

弊チームは、「RLSMeetup#7 プランナー・サイエンティスト・エンジニア三位一体!年間十数億稼ぐチームの舞台裏」のレポートにあるように、 一つのチームに複数人のプランナー・データサイエンティスト・エンジニアが在籍しており、 弊社におけるビッグデータを活用して利益創出することを目指したチーム体制となっています。

じゃらんなどの大規模なサービスでは、データ分析によるコンテンツ出し分けやレコメンドシステムの性能評価に A/B テストを用いており、 本稿では、そのようなデータドリブンな A/B テストを高速に回すための取り組みとして、 新たに開発した DevOps 基盤の導入経緯や仕組みについて紹介していきます。

A/B テストを高速に回すためには?

機械学習を含めたデータ分析を利用して有効な施策を生み出すには、データサイエンティストの知見が必要不可欠です。 しかし、データ分析が複雑化するほど、多くの計算リソースが必要になり、かつバッチ化 (システム化) の難易度が高くなることが問題になります。

そのため、データ分析を利用した A/B テストのサイクルを高速に回すためには、以下のような仕組みが必要であると考えられます。

  • データサイエンティストがクラウドのパワフルな実行環境を活用できる仕組み
  • データサイエンティストの分析用コードをシームレスにバッチ化できる仕組み

クラウドのパワフルな実行環境

言わずもがなですが、分析すべきデータの量は膨大です。 分析サイクルを速くしたり、深い分析したりするためには、クラウド上のリソースを上手く活用できるかが重要となります。

エンジニアであればクラウドのリソースを扱えますが、 理論系のデータサイエンティストはクラウド環境の利用を得意としない方もいます。 また組織によっては、アクセス権限のポリシーを細かく設定することで、セキュリティ面や金銭面の安全性を高める運用をしており、 クラウドが使いづらいものになっているかもしれません。

そこで、データサイエンティストでも追加の学習コスト無しで簡単にクラウドのリソースを活用でき、 機械学習を含めたデータ分析が実行できる仕組みがあると良いでしょう。

シームレスなバッチ化

機械学習などを含むシステムの開発では、まず理論寄りのデータサイエンティストがプロトタイプの分析用コードを作り、 それをエンジニアが受け取って本番環境で動くバッチシステムに仕立てるというフローが様々な現場で見られます。

いざデータサイエンティストが最高精度の機械学習モデルを作り上げたとしても、 そのソースコードがあらゆる意味で難解 (機械学習モデルそのものの難しさだけでなく、コーディング的な意味でも) で、 エンジニアによるバッチ化が困難を極める場面は往往にしてあるものです。

データサイエンティストが用意する分析用コードをシームレスにバッチ化できる仕組みがあれば、 エンジニアの負担が減り生産性が高まります。

このように解決しました!

そこで、我々のチームでは以下のような仕組みを作りました。

  • Github に上げた分析用コードを自動的にクラウド上で実行する実行基盤
  • 実行環境のコンテナ化・コードレビュー・バッチ移行作業を自動化するバッチ化基盤

基盤構成

auto-cloud-compute

主な構成は

  • コード管理: Github
  • CI/CD: Drone
  • 実行環境: Google Compute Engine (以下、GCE)
  • ログ出力: Stackdriver Logging (以下、Stackdriver)
  • ジョブ管理: Airflow
  • コンテナ化: Docker
  • 自動レビュー: Flake8, reviewdog
  • その他連携先
    • データウェアハウス: Google BigQuery (以下、BigQuery), Amazon Redshift (以下、Redshift)
    • ストレージ: Google Cloud Storage (以下、GCS), Amazon Simple Storage Service (以下、S3)
    • 通知: Slack

です。

分析用コードを自動的にクラウド上で実行する実行基盤

追加の学習コスト無しでクラウドのパワフルな実行環境を使えるようにするために、 Github の Commit, Push, Pull Request という通常の開発フロー (Github Flow) の中に、 暗に分析用コードが自動的にクラウド上で実行される仕組みを組み込みます。

処理の流れは以下の通りです。

  1. Github の特定のリポジトリへの Push をフックとして、Push された分析用コードを含めたリポジトリ全体を、分析コード実行用の Docker イメージとして Build & Push
  2. ユーザが定義した設定ファイル (MachineType や Region) に従って、Drone が GCE 上にインスタンスを起動
  3. Startup Script 機能を利用して、インスタンス起動時にシェルスクリプトを実行 (シェルスクリプトの実行内容は以下の通り)
  4. 先ほど作った Docker イメージを Pull
  5. コンテナを立ち上げ、分析用コードを実行
  6. 実行中のログは Stackdriver へ送信
  7. 実行完了後、Github や Slack へ StackdriverLogging URL や実行結果を通知
  8. 自インスタンスを削除

コンテナ化・コードレビュー・バッチ移行作業を自動化するバッチ化基盤

分析用コードをバッチ化するにあたって気をつけるべき点は以下の 4 つです。

  1. 分析実行環境では動いたが、バッチ実行環境では動かないということが無いようにすること
  2. コーディング規約が守られており、保守性が高いソースコードが用意されること
  3. ソースコード内に日付などの動的要素が固定値としてベタ書きされることを防止すること
  4. 分析用コードのバッチ化の工数を限りなくゼロにし、A/B テスト施策がどれだけ増えても実施できるようにすること

1 は、実行環境の Docker コンテナを共通化することで実現できます。
2, 3 は、Github に Push されたソースコードを後述の自動レビュー時に指摘されるようにすることで実現できます。
4 は、シェルスクリプトによって Airflow DAG への登録を自動化することよって実現できます。 DAG の処理内容は上記で示したものと同様に、インスタンス起動、Docker イメージの Pull、コンテナ起動、実行のみです。

以上のような仕組みを用意することで、分析用コードの実装からバッチ化までの作業工程は、 データサイエンティストが担うこととなり、エンジニアの工数はほとんど無くなります。 しかし、これによってデータサイエンティストへの負担が増えてしまっては意味がありません。 その回避方法は「工夫したところ」に記載しました。

工夫したところ

コードの品質・ルールを守る自動レビュー

前述した通り、データサイエンティストのコーディングスキルにはバラツキがあり、 品質の低いコードが生まれてしまうことがありますが、 大抵の場合そのコードを改善するのはエンジニアの仕事になりがちです。 これではエンジニアが疲弊していくのが目に見えています。

そこで、Github に Push されたコードに対して、 Flake8 を用いた自作プラグインによる自動レビューを適用し、 上で述べたバッチ化するにあたって気をつけるべき点を全てチェックできるようにしています。 また、違反している点については PR 上に修正コメントが付けられる reviewdog を導入しています。

auto-review

これにより、データサイエンティストはレビュー項目に従って自身でコードの品質を高めることができるようになりました。

様々なI/Oライブラリ

データサイエンティストが分析する際によく使う BigQuery や Redshift, GCS, S3 のような各種データソースに簡単にアクセスするためのライブラリや、 実行中のログを Stackdriver に出力するライブラリ、実行終了時に Slack や Github へと実行結果を通知するライブラリ、 または、A/B テスト施策別に必要な出力 IF をラップした出力ライブラリなど、 データサイエンティストでも簡単に使えるような I/O ライブラリを用意することで、 スムーズに機械学習モデリングを実装したり、A/B テスト施策に反映させることが可能になりました。

実装コードの自由度の高さ

用意された仕組みによって利用者が実装できるコードの自由度を下げてしまうと、 普段通りの実装が叶わなくなり、良い分析に対する阻害となってしまう可能性があります。

この仕組みでは、実装コードが Python であることと、下記に示す必要最低限の実装フレームに合わせること以外の制約をつけないことを心がけました。 これにより普段通りの実装で、これまで説明してきたような自動化が適用されるものとなりました。

1
2
3
4
5
6
7
@timeout     # タイムアウトデコレータ
@stacktrace  # 例外キャッチデコレータ
def main():
    # 任意の実装
if __name__ == '__main__':
    main()

※ import 文など、一部省略しています。

弊社の大規模案件に導入されています!

大規模案件では、多くのデータサイエンティストがそれぞれ機械学習を含めたデータ分析を行い、 様々なコンテンツ出し分けアルゴリズムやレコメンドアルゴリズムによってサービス改善に取り組みます。 しかし、実施したい A/B テストの施策数が多くなると、 その度にデータサイエンティストが作った分析用コードをバッチ化する作業が発生するため、同時に実施できる施策数に限界がありました。

この仕組みが導入されたことによって、バッチ化する作業が自動化され、コードの品質も高く保つことが可能になりました。 現在では、一つの案件で同時に 10 パターン以上の A/B テスト施策が実施される状況となり、高速なサービス改善に貢献しています。 また、同時に実施できる A/B テスト施策数が増えたことで、R&D としての実験的なテスト施策に挑戦する余裕をつくることができ、 データサイエンティストにとって挑戦しがいのある環境になりました。

注意しておくべき点

コードの品質・ルールを守る自動レビューでは、規約などの単純なルールについては指摘できるものの、 デザインパターンなどのコードアーキテクチャの指摘まではできないため、レビューとしては不完全です。 しかし、A/B テストは一時的かつ部分的にサービス適用されるものであるため、 ある程度コードの完全さを犠牲にして、テストサイクルを高速に回せることを優先する方が有益であると考えられます。

A/B テストの結果、恒久的かつサービス全体へ適用できると判断された場合については、 エンジニアによってアーキテクチャまで含めた再実装が行われると良いでしょう。 ここでも、自動レビューによりコードの品質が保証されていれば、再実装の工数も低減されることが期待されます。

終わりに

弊チームではこの DevOps 基盤によって、A/B テストのサイクルが劇的に高速化されました。
より素早い A/B テストのサイクルは、より高速なサービス改善に繋がるでしょう。

この仕組みは、簡単なシェルスクリプトと Docker によって構築されているため、 CI/CD ツールやクラウド、ジョブ管理ツールをお使いの組織であれば導入は容易です。 Drone は他の CI/CD ツールに、GCE は他のクラウド仮想マシンに、 Airflow は他のジョブ管理ツールに置き換え可能でしょう。

また、最近ではクラウドで機械学習などの分析や実行をサポートするサービスがどんどん追加されており、 我々のチームでは、Google Cloud ML Engineを活用した深層学習モデリングにも取り組んでいます。 現状に拘らず便利なものはどんどん導入していく所存です。

これからもデータサイエンティストとエンジニアが協業していくことで、まだここにない新しい価値を創造していきたいと思います! 弊社では、データ分析のための基盤を開発したいエンジニア、ビッグデータや様々な分析基盤を使って機械学習モデルを構築したいエンジニアを募集しています。