dbtで管理しているデータの可用性をelementaryで分析する

データの可用性を可視化したい

データ品質は正確性や最新性など様々項目に分解することができますが、可用性(Availability)はその中でも基礎的な項目です。使いたいときにデータが使えないと困るので。

自分が所属しているチームはdbt(cli)およびdbt cloudを使っていますが、可用性を考えるのであれば

  • cli: dbt runの実行結果
  • dbt cloud: Jobsの実行結果

をそれぞれ確認したり、こけているようであればアラートを飛ばすという運用が多いと思います。これだけだと「いつこけた」しか分からないので、Datadogを使って「いつこけた」「いつ復旧した」「こけて落ちていた時間はどれくらいか」がぱっと可視化できるようにしています。

データの可用性の解像度を上げたい: elementary-data

「dbtのバッチがこけた」という観点の可用性は上記の方法でよいですが、これは解像度がめちゃくちゃ荒いです。「どういうデータセット / テストがこけがちか」といった細かい分析をしたい場合に手も足も出ません。

こういったもう少し細かいデータ品質の分析や可視化を行なうのに便利なツールの一つがelementary-dataです(名前が長いので、以降はelementaryと呼びます)。

SaaS版もありますし、OSS版もあります。今回はOSSを使います。基本的な使い方は適当にぐぐって欲しいですが、今回のスコープでは以下の修正だけでさっと動かすことができて簡単です。

  • packages.ymlに依存パッケージを追記
  • dbt_project.ymlに出力先のデータセット情報などを追記

elementaryによる細かい可視化

pip install elementary-dataを実行すると、edrというコマンドが使えるようになって、見やすいhtmlのレポートの生成やSlackへの通知なども行なうことができます。htmlのレポートは特に便利で、特定のテーブル / テストの実行結果の推移や実行時間の推移を可視化することができます。

elementaryが担う役割としてはこの「推移」がとても重要です。推移が分かることで

  • 最近BigQueryのコストが増えている
    • 実行時間が特にかかっているテーブルはどれかelementaryで調べる
      • Median exec. timeで生成に時間がかかっているテーブルがさっと分かる
    • 7/1以降にぐっと実行時間が伸びているみたいだ、このテーブルに関係するこの辺の修正コミットを調べてみよう
  • 特定のテーブルが最近よくこけている
    • ...気がするんだけど、何となくな肌感
    • しかし、elementaryだと生成に失敗(orスキップ)された場合は赤点で表示される
    • 客観的な数値で可用性が分かる
      • 上の画像のテーブルだと大雑把には55/56 = 約98%は可用性が担保できていると言えそう

といった分析や判断に繋げることができます。

大雑把にデータセット単位で可用性を可視化したい

elementaryによる可視化は便利ですが、今度は少々細かすぎます。提供しているテーブルが10以下とかならよいですが、数百とかになると個別テーブルの単位で認知するのは無理です。権限管理などと同様にデータセットやタグなどある程度グルーピングされた単位で可用性も見たくなることが多いでしょうし、SLAなどもそういった目的や用途に応じて設定することが多いでしょう。

elementaryは分析元になっている情報も蓄積してくれているので、それを独自に分析すればデータセット単位で可用性*1を可視化することができます。dailyで実行しているバッチの可用性を可視化したいのであれば、例えば以下のようなSQLを書けばよいです。

WITH tmp AS (
  SELECT
    DATETIME(CAST(dbt_run_results.generated_at AS TIMESTAMP), "Asia/Tokyo") AS generated_at_jst,
    dbt_models.schema_name AS dataset_name,
    dbt_models.name AS table_name,
    dbt_models.tags,
    dbt_run_results.status,
  FROM
    `my_project.my_elementary.dbt_run_results` AS dbt_run_results
  LEFT OUTER JOIN
    `my_project.my_elementary.dbt_models` AS dbt_models
  USING
    (unique_id)
  WHERE
    resource_type = "model"
)
SELECT
  DATE_TRUNC(generated_at_jst, DAY) AS generated_at_jst,
  dataset_name,
  tags,
  SUM(IF(status != "success", 1, 0)) AS cnt,
FROM
  tmp
GROUP BY
  generated_at_jst,
  dataset_name,
  tags

dbt_run_resultsにdbtの個別の実行結果や実行時間などが格納されていて、dbt_modelsに個別テーブルのデータセットやdbtで紐付くタグの情報などが格納されているので、それをJOINしているだけです。簡単ですね。なお、今回は簡単のため復旧時間については考慮しないものになっています(すぐに復旧させた場合と丸一日落ちていた場合を同様に扱っている。最悪ケースを可視化していると考えればよい)。

このSQLを実行すると、以下のようなグラフが得られます。

なお、上記のグラフは適当に乱数を混ぜたデータになっているので、あくまでイメージですが

  • 横軸が日付
  • 縦軸が実行が失敗したテーブル数(データセット毎色が違う)

という形式です。こういったグラフを可視化することで、例えば以下のようなことが分かるかもしれません。

  • よく落ちているデータセットはどれか
  • 復旧までにかかっている時間はどれくらいか
  • 障害の原因になったデータセットはどれか
    • 多数のデータセットやテーブルに影響が出ているが、要因は一つのテーブルというのはよくある
    • そういったテーブルのリリースやレビュー時により気を配るようにする工夫ができるかもしれない

今回は可用性の可視化を行ないましたが、resource_type = "tests"を対象にすれば、他のデータ品質の可視化も割とすぐに行なうことができるかと思います。

まとめ

elementaryを使ったデータの可用性の可視化について紹介しました。

「バッチの実行結果では解像度が粗すぎる」「とはいえedr reportの結果は細かすぎる」という場合にelementaryが生成してくれる生のデータを自前で分析することでデータセットやタグの単位など自分たちが欲しい粒度で可用性を可視化できます。データ品質、やっていきましょう。

*1:dbtがfail / skipされ、テーブルができていない / 更新されているかいないかで可用性を定義しています