下町柚子黄昏記 by @yuzutas0

したまち発・ゆずたそ作・試行錯誤の瓦礫の記録

私の考えた最強のログ&モニタリング設計

この記事はRecruit Engineers Advent Calendar 2018 - 8日目の記事です。

注意点

  • タイトルは煽りです。「新規事業におけるデータエンジニアリングの勘所」の方が正しいかもです。
  • クオリティというか記事の信頼度は、投稿時間がギリギリになってしまったことから察してもらえるとありがたいです。
  • 本エントリーの内容は個人的な見解であり、所属する組織を代表するものではありません。データの取り扱いは非常にセンシティブなトピックでもあるため気軽に発信すべきではないということは重々承知しております。もし誤りや考慮不足だと感じる点があれば、それは全て私個人の力不足によるものですので、どうぞ私個人当てにご指摘のコメントをいただけると幸いです。

もくじ

背景

機械学習を活用した新規事業(WEBサービス)をゼロから立ち上げることになりました。 そこで初期フェーズにおいて、どのようなログ・モニタリング設計が望ましいかを自分なりに整理しました。 なお、大人の事情で詳細は書けないので、曖昧な記述やフェイク情報を交えています。

まだ試している最中なので、確立したプラクティスではありません。 「もっとこうしたほうが良いのではないか」といったご意見をいただければ幸いです。

前提

まず前提情報として体制とシステムを提示します。 ログの取り方はシステムに依存し、そしてシステムのアーキテクチャは体制に依存するからです。

体制

f:id:yuzutas0:20181208233306p:plain

ビジネスチーム、開発チーム、機械学習チームの3つで考えます。 本来ならデザイナーやカスタマーサポートやマーケッターにも言及すべきだとは思いますが、あえてこの体制の切り方で説明します。

特筆すべきは機械学習チームです。 昨今のビジネスにおいて機械学習をどう活用するかはホットなテーマです。 現時点ではスキルがコモディティ化・普及しているとは言えず、体制はどうしても分かれてしまいがちです。1

ログやモニタリングを整備するデータエンジニアは、これら3つのチームと横断で関わる存在です。 可能であれば専任の推進者を1人置くことが望ましいでしょう。 全ての論点を理解できる必要はありませんが、各ステークホルダーの要求を整理できる人材だと話がスムーズです。

f:id:yuzutas0:20181208234012p:plain

ログやモニタリング、データ分析の観点から全体を見ると、要求・要件の抜け漏れや計画の不備に気付くこともあります。 そのときはプロダクトマネージャーならびにプロジェクトマネージャーにアラートを上げることになります。 一気通貫で各論まで踏まえて企画できるPMは普通の企業にはいないので、むしろ自分で大上段を整理するくらいの気概があると良いかもしれません。

f:id:yuzutas0:20181208234150p:plain

通常のシステム開発フローの場合、モニタリングや分析の不備に気付けるのはリリース後、最後の最後です。 専任者を置かず、開発工程の早い段階でデータ設計の品質を担保しないと、後工程に課題を押し付けることになります。 結果としてBuild・Measure・Learnというプロダクト検証サイクルの放棄に繋がります。

システム

f:id:yuzutas0:20181208234224p:plain

フロントのアプリケーション(iOSAndroid、WEB)、それぞれのBFF、バックエンドWebAPI、データストア、インフラ、機械学習サービスWebAPIを構築します。 ただし開発優先度としてモバイルアプリは後回しにします。 また、インフラ(GKE)、モバイルアプリ(Firebase)、データ分析(BigQuery)、マーケティング(Adwards)などのシステム連携観点を踏まえて、フルGCPで構成します。

開発スコープ

初期フェーズではユーザーが使うシステムのみをメインの開発スコープとします。 手間暇かけて内部向けシステムは最初は作り込まないということです。 また、決済システムのように、法的観点で考慮事項が多い機能・高い品質が求められる機能も、初期スコープから外します。

地方の中小企業を支援するECサイトで、売買手数料を取るようなビジネスモデルであれば、DBの売買データをもとにして手動メールで請求書を送るところから始めます。 この手の業務はフローを確立させるために検討しなければいけない事柄が多いです。 時間を掛けてシステムを構築して、いざ運用を始めたら「もっとこうすればよかった」という学びが山ほど出てくるものです。 そのため最初からシステムに全てを反映させず、運用を通して要件を磨き込みます。 ただし業務に必要なデータをBigQueryから取得できる仕組みは担保します。

機械学習WebAPIは分離

ECサイトの商品レコメンドであれば、ユーザーIDを受け取って、おすすめ商品リストを返すようなWebAPIを想定します。 あるいは商品掲載チェックの自動判定(不適切な商品・画像・テキストの登録を弾く)といったWebAPIも考えられます。

前述の通り、WEB開発スキルと機械学習スキルの持ち主は、現時点だと別チームになりがちです。 そのためモノリシックにまとめるのではなく、それぞれのチームが独自に磨き込めるようにシステムを独立させます。 ロジックを切り替えたり、ABテストを実施しやすいというメリットもあります。

最初のWebAPIでは未加工のレスポンスを返すことになるでしょう。 レコメンド機能ならランダムでアイテムを返してI/Oだけ担保する形になります。 というのも初期フェーズにおいては絶対的にデータが足りないため、機械学習が効果を発揮しにくいからです。

強いていうなら、想定される類似データで学習させたり、仮説をもとにしたルールベースのロジックから始めることになります。 プロダクトとしては機械学習の機能がなくても顧客がお金を払う価値や体験デザインを作り込まなければなりません。

ある程度データが溜まってきたらダークローンチを行います。 機械学習WebAPI(未加工レスポンスだけ返す)の本番リクエストログをもとにして、独立環境でシミュレーションを行います。 ユーザーには影響を与えずに、開発者や運営者が裏側で精度を確認します。 問題なさそうなら、まずは10%のユーザーを対象にして、カスタムレスポンスを返すようにします。 あとは徐々にシステムを実稼働させます。

データ基盤設計

こうした体制・システムを踏まえた上で、どのようにログ・モニタリングを整備していくか。 データの流れをもとにして各トピックにおけるポリシーと実行方針を述べていきます。

f:id:yuzutas0:20181208234259p:plain

なお、データレイク(元データのコピー)、データウェアハウス(業務ドメイン知識を反映した中間データ)、データマート(用途向けの加工済みデータ)の概念は区別して考えます。 ただしデータレイク・データウェアハス・データマートは全てBigQueryで管理します。 詳しくは以下のエントリーを参照ください。

yuzutas0.hatenablog.com

全体の設計ポリシー

ビジネスの勝ち筋を模索する初期フェーズにおいて、過剰実装・早すぎる最適化は回避します。 作り込んでしまうとシステムが重厚長大になってしまうため、ビジネスの期待するアジリティを実現できなくなるからです。 俗な言い方をすると「なるべく楽をする」ことが重要となります。 最低限の要求に対して迅速に応えながら、屁理屈をならべて徹底的にシステムをシンプルに保ちます。

データソース(ログ)

ポリシーとしては(無理のない範囲で)「取れるデータはなるべく取る」です。 捨てたログを後から取ることはできません。 ログさえ手元にあれば後からデータレイク(BigQuery)に連携できます。 とにかくログは取っておきましょう。

ということでログ収集のために各ツールを導入します。 特別な理由がない限りはデファクトスタンダードと言えるものを提示します。 開発エンジニアが実装で大変そうだったら、代わりにデータエンジニアがプルリクを出しましょう。

  • モバイルアプリ
    • アクセス解析ログ: Firebase Analytics
    • クラッシュレポート: Firebase Crashlytics
  • フロントエンド
  • バックエンド
    • アクセスログ(ApacheやNginxで吐き出すログ): GKEの場合は Stackdriver Logging にデフォルトで出力される
    • アプリケーションログ・エラーログ: Spring Bootの場合は SLF4J + log4j でプロジェクト用の共通Loggerを設定すると、最終的には Stackdriver Logging に出力される
  • DB: PostgreSQL by CloudSQL などのRDBMS
    • 画面表示などWEBサービスの機能要件を満たすためのデータを保持します
    • データ活用観点で余計なことをやろうとするとアプリケーションを含めてシステムが汚れてしまうので最小限の設計に留めます
    • 常に最新のER構成を確認できるように、MySQL Workbench などのツールでDDLファイルをバージョン管理できると最高です

ログに関する実務上の論点についていくつか補足します。

共通ログ基盤について

独自SDKを入れてフロントエンドでもiOSでもAndroidでも同じログを飛ばすような仕組みを設けているところもあります。 意見が分かれるポイントなのですが、以下2点の理由から、共通ログ基盤は不要かなと私は思います。

  1. 共通基盤部隊がSDKを保守するのは結構大変だから
  2. 特定デバイスだからこそ取れるデータを削ぎ落とすことになりがちだから

データサイエンティストからすると「とりあえず全部データ入れといてくれよ」と言いたくなる場面はよくあります。 入り口であるログの形式を共通化すると、確かに後のデータ結合は楽になります。 しかし、本来はデータウェアハウスで吸収すべきであって、ログ収集時点でジャッジするのは適切とは言い難いのではないでしょうか。 余計なことをせずにデファクトスタンダードのツールをそれぞれ活用してデータを送るのが結果として最適だと思っています。

個人情報保護・通信の秘密

POSTメソッドで送られるリクエストbodyやDBに登録する情報の取り扱いには注意しなければいけません。 データをそのまま垂れ流すわけにはいかないのです。

端的にまとめると以下のジレンマが生じます。

  • 障害対応の文脈では(法令や利用規約やプライバシーポリシーの範囲内で)なるべく詳しい情報まで見られる状態にはしておきたい
  • なるべく手軽にデータを分析・活用するためには、守るべきデータはマスキングしておきたい

つまり「基本的には見せないけどデータとしては後で調査可能にする」必要があります。

フルGCPならセキュア環境(プロダクション)とマスキング環境(分析)の二重構成にするのが妥当ではないかと考えています。 例えばStackdriver Loggingには「除外フィルタ」という機能がありますが、これはログを丸々遮断してしまうようで、障害対応の文脈ではベストとは言い難いです。

なかなか難しいのですが、1つの案としてはログはそのまま出して、後述のデータレイク(BigQuery)の時点で二重構成にしたらどうかというのが今の自分の考えです。 データソースのシステム構成に依存せず、セキュアBigQuery to マスキングBigQuery の受け渡しSQLにおいて、取り扱うデータを制御するのが一番簡単ではないかという案です。

DBに残さないログの取り扱い

サイトの機能としては不要だが、分析としては使いたい、というデータはあります。 例えばUpdateやDeleteの更新履歴を追いたい場合です。 正直なところ実装方針は悩んでいるのですが、いくつか方法はあります。

  • Google Analytics: DBトランザクションの世界から遠すぎるのでNGです
  • DB: 使わないデータを置きたくないのでNGです
  • アクセスログ: 実装方針によります
    • WebAPIがRESTfulかつセキュアデータの管理方法が上記でOKならアクセスログで良さそうですね
    • UpdateやDeleteのエンドポイントをコールして200を返しているログがあれば、それは事実上の差分ログと言えそうです
  • アプリケーションログ: 無難だと思います
    • DBアクセスするRepositoryクラスの共通ロガーのようなものを作れば……
    • トランザクションと完全一致はしないけど、すぐ出来てそこそこの品質にはなる気がします
  • DB差分ログ(MySQLのbinlogなど): 品質としてはベストです
    • ただBigQuery連携で「これを使えばすぐできる!」というツールを今のところ知らないのです
      • Debezium はすごそうだけど Kafka は運用したくないのです
    • マルチマスタ構成のときに素直にbinlogでOKなんだっけ、というのは超絶調査中
    • マルチマスタDBのトランザクション管理は、普通のシステム運用の文脈においても障害対応で色々とハマった記憶があって、さらにそこをデータ基盤向けにハックするのは正直やりたくねぇ
    • 詳しい人がいたらむしろ教えてほしいです

データレイク

ポリシーとしては「流せるデータはBigQueryに流しておく」です。 データに関しては「とりあえずBQを見よう」と言える世界を担保します。

各データソースからの具体的な疎通方針は以下の通りです。

  • Firebase (Analytics / Crashlytics):
    • Braze Plan(従量課金)でBigQuery Exportが利用可能
    • Analytics と Crashlytics だけなら費用は抑えられる
  • Google Analytics:
  • Stackdriver Logging: Logs Export で BigQuery に自動で流す
  • Cloud SQL: GCSにエクスポートしてBigQueryに流す
    • ちなみにGCP以外の場合であればDBはRead Only Replicaからdumpするのが望ましいかなと思います
    • 改修の度に負荷調査や試験の工数が掛かったり、エラーの度にリトライタイミングの調整が必要になるためです

データセット命名規則source__データソース名 とします。 例えば source__dbsource__firebase__ios です。 アンダーバー2つで要素を区切り、必要に応じて source__aaa__bbb といった命名もOKとします。 データソースと1対1の関係になるので名前は機械的に決まるはずです。 意味を解釈する必要はありません。 コスト効率・処理パフォーマンスの観点から、イベント系ログは source__db.event__yyyymmdd のようにパーティションテーブル管理とします。

データの疎通頻度について。 サービスとしてエクスポート機能が提供されているものはその仕様に準じます。 そうでないものは日次のバッチ疎通から始めます。 リアルタイム性が求められるユースケースは、アドテクや人命に関わる機器の温度管理など、一部に限られるだろうという前提のもとです。 将来的には「ECサイトで在庫のない商品をレコメンド」といった機会損失を抑えるためにリアルタイム疎通の仕組みを別途設けることになります。

BigQueryの保存データはScheduled Queryで定期的にGCSバックアップを出力します。 上書き保存ではなくスナップショットを追加し続けます。 権限管理の不備やオペミスで、データレイクに予期せぬ変更が入ったときは、GCSからデータ遡求を行います。

データウェアハウス

初期フェーズでは絶対に作りません。 データマートが肥大化して、データパイプラインを構築した後に検討を開始します。 命名規則warehouse__ビジネスドメイン名 として、意味を解釈します。

データマート

初期フェーズでは原則的に作りません。 ただし後述するモニタリングの運用方法によっては、DataStudioで表示するためのテーブルを作る、といった可能性もあります。

命名規則mart__利用用途名 とします。 利用用途と1対1の関係になるので名前は機械的に決まるはずです。 意味を解釈する必要はありません。

データパイプライン

初期フェーズでは作りません。 単体の定期ジョブがいくつかある状態とします。 Scheduled Query による定期実行で十分管理できるはずです。

データマートが肥大化して、モニタリングの障害が頻発したタイミングで検討を開始します。 ただしその場合もまずは使っていないデータマートの除却から始めます。 不要なマートを除却したら、実際に使っているのは少数のデータだけということは往々にしてあります。 オーバースペックなパイプラインを組むほうが高コストになりかねません。

理想のシステムを作ることを目的化しないように心掛けます。 「具体的に何が課題か」を突き詰めて「データパイプラインを作ることが妥当な打ち手だ」という状況になってから着手します。 その際は Cloud Composer (Airflow on GCP) あたりを使います。

データ活用

主な活用用途として、業務・モニタリング(BI)・機械学習の3つについて述べます。

業務フローにおけるデータ参照

業務フロー上で必要となるデータ参照を洗い出します。 前述の例ですと、ECサイトにおける請求メールが該当します。

BigQuery で Read Only な User を発行して、手順書とSQLをオペレータに受け渡します。

-- イメージです
SELECT
  業者.id,
  業者.名前,
  COUNT(売買.id) AS 売買件数,
  SUM(売買.金額) AS 売買金額,
  手数料率,
  SUM(売買.金額) * 手数料率 AS 請求金額
FROM
  売買__201812* AS 売買 -- ここに請求対象となる年月(2018年12月)を入れてください
INNER JOIN
  売買.業者id = 業者.id
GROUP BY
  業者.id

モニタリング・BI

要件の優先順位をつけて(無理のない範囲で)データを見ます。 モニタリング観点は多々ありますが、ここではプロダクトマネジメントのトライアングル(ビジネス・ユーザー・デベロッパー)を切り口として洗い出します。

f:id:yuzutas0:20181208234400p:plain

引用元:The Product Management Triangle - PRODUCT LOGIC

集客やSEOの磨き込みのためのモニタリング、カスタマーサポートの対応リードタイム、開発チームのベロシティ、機械学習のABテスト結果モニタリングなど、論点は多岐に渡ります。 上記の3要素を徹底的に分解すれば(理屈上は)出てきます。 が、そこまで分解できないという場合は、業務フローをベースにしてKPIを設計すると良いでしょう。 ただし業務フローベースのKPIを過剰に追求しても、業務は回るが利益が伸びにくいこともあります。

これらの指標は全てを重視するというよりは、ウエイトを置くほうが望ましいです。 ECサイトの例ですと、購入実績が1万UUになるまでは体験を磨き込むフェーズとしてカスタマーサポートに力を入れて、そこから10万UUまでは拡大フェーズとして集客やSEOに力を入れる、といった具合です。 限られたリソースで優先順位を付けてモニタリングを整備するということは、コミットするためのKPIを考えるということであり、事業開発を推進するということです。

なお、初期フェーズにおいて無理にデータを繋げて分析する必要はないと考えています。 なぜならデータがそもそも足りていないからです。 ユーザーの元に直接出向いて、実際にサービスを使ってもらう。 その様子を隣で10分ほど観察させてもらう。 データ解析に1日を費やすよりも、より適切なインサイトを得られるでしょう。

また「施策Xと施策Yのどちらを先にやるか」を徹底して考えるよりも「さっさと両方やる」方がROIが高いこともあります。 ABテストをしたほうが効率的に回答を得られることもあります。

1万店舗がECサイトに出品することが当面のゴールだとしましょう。 既存のデータをこねくり回しても勝ち筋は見えないはずです。 100店舗に電話して「それなら出品しますよ」と店舗オーナーに言ってもらう。 そのためのセールストークというか、いわば殺し文句を突き止めることが大事です。 その殺し文句こそが店舗オーナーがこのサービスに抱く期待です。 その期待を満たす・超えるようなサービスにすれば良いはずです。

したがって、初期フェーズにおいてはインサイトを得るためというよりは、キードライバーの仮説を立てた上で数字が伸びているかチェックしたり、明らかな水漏れがないかを確認したり、いわば健康診断としてのモニタリング整備が重要となります。

機械学習のためのログ

前述のように機械学習のWebAPIをダークローンチする場合について述べます。 「精度が妥当か」(計測)と「精度向上のために何ができるか」(アクション)を見極めるためのデータ活用となります。 実務としてはデータレイクからデータをぶっこぬいて Colaboratory(Jupyter Notebook)をこねくり回すことになるでしょう。

レコメンドであればスコアリングを独立環境でシミュレーションします。 空振りであっても機械学習WebAPIをコールして、アプリケーションログとしてI/O(受けたデータ・返す予定のデータ)を垂れ流します。 そのシミュレーション結果を定期的に目視確認して「これなら行けそうだ」とステークホルダーが判断してからのリリースになります。 そして10%リリースから始める。このあたりは既に述べた通りです。

そこまでして初期に機械学習のシステムモジュールを挟むべきでしょうか。 リソースに余裕があるなら(例えば大企業における新規事業なら)初期フェーズからやるべきだと、現在時点では/個人的には思っています。 「こういうログの取り方だとレコメンドAPIには使いにくい」「こういう項目をユーザーから取得できると精度が上がりそうだ」といった、機械学習観点での学びやフィードバックを早期に得ることができるからです。

「うちにはデータがある」と思い込んでいる企業の大多数が、とてもではありませんが実用に耐えられないデータしか持っていません。 クレジングで疲弊するか、もしくは精度向上に寄与しません。 多くのビジネス担当やアプリケーション開発者は「機械学習を使ったサービス」のあり方にまだ慣れていません。

だからこそ、早い段階でデータ活用のフィードバックサイクルを回せるということは、ビジネス・システム・チームが「機械学習を使ったサービス」のあり方を踏まえた適応・進化を加速させることに繋がり、やがては競合優位性になるのではないでしょうか。

まとめ

勝ち筋の定まっていない初期フェーズにおいてはフィードバックサイクルを高速に回すことが求められます。 データ活用という文脈においては「ログはなるべく全部取る」「過剰なシステムを構築しない」の2点に尽きるかなと思います。 そこで浮かせた人的資源を「組織のデータ活用支援」に投下することがポイントかなと思います。


  1. モバイルアプリ開発が参考になるのではないでしょうか。かつてはモバイルアプリとWEBサイトの開発チームは分かれていましたが、今だと一気通貫でやっている開発チームが増えています、。同様に機械学習についても今後コモディティ化はある程度進むのではないかと思います。