オンプレDWHをBigQueryに移行した話

OGP

はじめに

こんにちは。MA部MA施策・運用改善チームの辻岡です。MA部では、ZOZOTOWNのメルマガ・アプリPUSH通知などの配信・分析等の用途で約数十TBのデータを運用しています。今回は長年MAのデータ基盤として利用してきたオンプレDWHをBigQueryに移行したおはなしをします。

この記事はこんな方におすすめ

  • オンプレDWHからBigQuery移行を検討・実施してる方
  • ジョブ・スケジューラ、ETLツールの移行を検討・実施してる方

概要

オンプレDWHからBigQuery移行する前後の構成イメージを元に、今回の移行の話について概要を説明します。

次の図が移行前の構成図です。オンプレ環境のWindowsサーバ上でジョブ・スケジューリングと実行を基盤処理として、データウェアハウス(以後オンプレDWH)に対してデータ生成や外部システムとの連携をしていました。

before_1

今回、以下を目的にオンプレDWHを廃止してBigQueryにデータを集約しました。

  • 分析効率化
  • 更なる発展性の向上
  • オンプレDWHの運用負荷を下げる

その後、移行スコープを検討した結果、オンプレDWHの移行だけではなくオンプレDWHに直接関連するオンプレWindowsサーバ上の処理全てをGCPへ移行することにしました。

既存のオンプレ基盤処理のままオンプレDWHだけ移行した場合、BigQueryへの接続すら既存のライブラリでは困難な状態でした。よって、オンプレDWHの移行だけではなくオンプレ基盤処理を一緒に移行する方が、安全かつ効率的に移行できると考えました。そこで、以下のように移行を進めることにしました。

before_3

移行した結果がこちらです。2022年1月に移行しました。

after_1

なんということでしょう。オンプレDWHをBigQueryに移行するだけでなく、オンプレ環境をまるっとGCPに移すことでとてもシンプルな構成に様変わりしました。

次は、移行前の課題と解決策についてお話しします。

オンプレDWHについて

オンプレDWHはメルマガなど各種配信用のデータやその実績データを格納しており、約10年もの間MAのデータ基盤として利用されてきました。

課題

オンプレDWHでは、社内外含めて当該DWHに関する情報不足かつ独特な運用のため、保守・運用負荷が高い状態でした。さらにクエリの並行数には制限があるため、分析者が気軽にDWHにクエリを実行できない課題がありました。

解決策:BigQueryへ移行

そこで、移行先としてBigQueryを選択しました。著名かつクエリの並列実行が可能な数も(slot数に応じた遅延はあれど)いくらでも増やせるBigQueryは先の課題を解決してくれます。また、全体的なデータ基盤として既にBigQueryが採用されていたため、BigQueryへデータ集約することにしました。

オンプレ基盤処理について

オンプレDWHをメインのデータソースとする基盤処理がありました。基盤処理は、Javaを使ったSQLの実行処理やメール配信SaaSへのリクエスト、ファイル生成処理等をオンプレ環境のWindowsサーバ上で行っていました。

課題

オンプレ基盤処理では、古いバージョンのライブラリを使った処理が複数存在し、環境に関しても開発と本番で分離がされていませんでした。また既存のオンプレWindows環境を含めて知見者も不足している状態でした。この基盤でBigQueryへ移行すると接続方法ですらボトルネックになり、開発効率も下げるリスクがありました。さらに、オンプレ環境への接続都合により、リリース時は必ず手動でのデプロイ作業が入っていました。

解決策:Digdag on GKEへ移行

課題の解決策として、GKE上に作成したDigdagへ移行することを選択しました。オンプレ基盤処理でも既にワークフローツールが使われており、既存の基盤をやめるにしても類似の機能が必要でした。MAでは既に別の処理でDigdagを利用しており運用経験や知見が豊富だったこともあり、Digdag on GKEという統一したバッチ処理基盤を作ることにしました。

クラウド移行する場合GCPを使うことは予め決まっていたのですが、GKEを使う事でよりスケールが楽な状態になりました。

例えば、ファイル連携処理の中でそれなりに大きいファイルの文字コード変換や加工によってリソースを消費する処理がありました。ですが、KubernetesCommandExecutorのおかげで他のtaskへの影響はなく、taskに対してpodのリソース設定するだけで問題なく実装できました。他にもたくさん恩恵を受けていますので以下のテックブログをぜひご覧ください。

techblog.zozo.com

また、GitHub Actionsを利用してリリースを自動化しました。

移行手順と工夫

ここからは、リプレイスの泥臭い過程をお話しします。技術的な話はあまりありません。これから移行を実施する方の少しでも事例の参考になればよいという目的で書いています。興味のない方は、この後の"今後の展望"あたりまで飛ばすことをお勧めします。

移行は以下のように行いました。

  • クエリのリファクタリング
  • 解体新書の作成
  • 未知の領域、夜間バッチからスタート
  • アプリケーションのリプレイス実装
  • クエリ切り替え
  • 移行テーブル洗い出し
  • 進行期間中にあった移行前基盤の過不足の反映

クエリのリファクタリング

2020年の10月辺りから2021年の5月頃まで、ビジネス案件と並行しつつ移行対象のクエリの一部リファクタリングを移行前に行いました。リファクタリングすることにより処理内容を把握できるといったメリットがありました。

解体新書の作成

ドキュメントがなく、処理が複雑でも、リプレイスは既存の処理を必ず知る必要があります。複雑な処理はリプレイスのためだけに既存の処理の流れを書いたドキュメントを作りました。私はこれを「解体新書」と呼んでいました。本物の解体新書とは一切関係ありませんが、作成経緯は似たようなものを想像しました。嘘じゃないよという証明を兼ねて、当時のドキュメント件名の一部を載せておきます。

document

実装前の内部を把握する目的は果たせたので実施効果はあったと考えます。

未知の領域、夜間バッチからスタート

一番最初に手をつけたのは夜間バッチと呼ばれる処理でした。これは、その名の通り夜間に動く処理です。移行前に使っていたジョブ・スケジューラは、GUIでぽちぽち処理フローを作ることができました。歴代の処理注ぎ足し運用により、蜘蛛の巣のようにジョブが連なっている状態でした。念の為モザイクをかけさせてもらいますが、以下の図が移行前の夜間バッチの処理フローの一部です。図のコメントはわかりやすいように追記したものですが、このGUIと中の処理を見ながらDigdagのWFを実装していきました。

mkt

夜間バッチから手をつけた理由は2つあります。

  • 夜間バッチに依存している処理が沢山あったから
  • 誰一人全てを知ってる人がいないパンドラの箱状態だったから

1つめは夜間バッチに依存してる処理が沢山あったため、先に作っておくとその後のリプレイスがスムーズになると考えたためです。2つ目は一番先行きの見えないこの処理を移行しておくことで終わりの見通しを良くするためです。

実際に夜間バッチの移行実装後はリプレイスの見通しがよくなり、プロジェクトの進行がスムーズになりました。よって一番見通しがつかないかつ依存関係の多い処理から移行することは、プロジェクトの進行に大きく寄与しました。

手を動かすことで先が見えない状態から、少し先行きが見えてきた状況の変化が大きな進歩でした。とにかく不明点を潰しながら移行作業をすることで、実装速度を上げる効果があったと考えます。

アプリケーションのリプレイス実装

続いて、ジョブ・スケジューラと既存のソースを読みながらDigdagに処理を移行していきました。バッチの各処理の区切り、クエリの区切りを読み取り、taskをなるべく細かく切ってWFを組みました。例えるとひたすら因数分解をするような作業です。リファクタリングの意図もありましたが、因数分解をしないと難読なコードやクエリが多く、ある程度整理したかったことが本意です。BigQueryの実行にはDigdagのbqオペレータとPythonを使いました。この辺りは以前Meetupで紹介した以下の資料に載ってますので興味のある方はご覧ください。

speakerdeck.com

オンプレDWHからBigQueryのクエリに切り替え

続いてクエリをオンプレDWHの文法からBigQueryの文法へ書き換えました。

オンプレDWHの文法とBigQueryの文法の互換性に関する公式ドキュメントは存在しました。しかし、利用しているクエリは公式ドキュメントにない記法が随所にありました。そのため簡単な変換ができる場合に限り変換スクリプトで変換しましたが、基本的には1つ1つ手動でクエリを切り替えました。特に以下に留意しながら進めました。

  • Timezoneについて、オンプレDWHはJST、BigQueryはUTCであることを考慮
  • Query is too complexエラー回避
  • テーブル名をアッパーキャメルケースにした

1つめは、BigQueryの既存データが既にUTCで入っていたので合わせてクエリを変えることです。日付チェックが多いのでDATE(target_date, 'Asia/Tokyo')のようなJST変換を全てのクエリに対して行いました。2つめは、BigQueryに携わる誰もが遭遇したであろうクエリの複雑性によるエラーの解消です。これは、クエリを細かく刻むことで解消しました。

最後は少し毛色が違いますが、テーブル名を全て大文字(例:USERTABLE)からアッパーキャメルケース(例:UserTable)に変えました。BigQueryはテーブル名の大文字と小文字を区別するため、この機会しかないと踏んで切り替えました。

上記と同等に留意すべき点だったのに漏れてしまったことが1つありました。それは処理が動く時間です。例えば、翌日用の処理が前日の夜に動き前日データを削除したい場合、指定するのは昨日ではなく今日を指定する必要がある、といったケースです。ほとんどの日次データ生成処理は利用当日の深夜に行う処理が担っていたのですが、前日に翌日分のデータを生成する処理は存在し、残念ながらリリース後にその考慮漏れを発見する形となってしまいました。今思えばとても単純な事とはわかりつつ、同じ境遇の方が同じミスをしないように、考慮不足の例も併せて記載しました。

データ移行対象テーブルの洗い出し

続いて、どのデータをどのように移行するのかをまとめたテーブルリストを作成しました。以下はリストの例です。

table_mapping

毎日洗い替えを行うデータの場合はデータ移行不要ですし、積み上げデータの場合はデータ量に応じてデータ移行の時間がかかる可能性を踏まえ、例のようにデータについての特徴を洗い出しました。

移行期間中に行われたオンプレ基盤処理での修正差分を反映

運用によるオンプレ基盤処理の改修は移行期間中も行なっていたため、移行後の基盤に反映しながら進めました。差分反映は二重の実装期間がかかることはもちろんですが、反映漏れやバグのリスクも増えます。リスクをなるべく避けるため、ビジネス部門と交渉し移行期間中はオンプレ基盤処理の改修を最小限に留める調整を実施しました。

移行直後に発生したこと

リリース直後に不具合が発見され、その修正対応に約1か月ほど費やしました。処理自体のエラー検知はDigdagが行ってくれますが、データの中身についてはデータチェック処理や各種検知をリプレイス前と同等の仕組みしか入れなかったため不十分な状態でした。また、GUIのジョブ・スケジューラが廃止されたことでビジネス側の運用効率が大きく下がったと報告を受けました。さらに冪等でない箇所があったこととGKEでの運用スタートがあいまって、自部門のアラート対応負荷も上がりました。開発改善を行い、前述の通り稼働後1か月程度でこれらを安定稼働といえる状態までに収束しました。

移行結果

課題は解決したのか

分析効率

アプリケーションと分析用でBigQueryのJob実行プロジェクトを分けることで、アプリケーション処理に影響なく、分析者がクエリを実行できるようになりました。移行前はオンプレDWHを使った分析の代替方法として、夜間にオンプレDWHからBigQueryに連携してBigQueryから分析していました。しかし、データが1日遅れのためリアルタイムな分析ができない状態でした。また、連携が遅延するとさらに分析が遅れるリスクも負っていました。BigQuery移行後はリアルタイムにBigQueryへデータ格納されるようになったので分析効率は上がったと言えます。

発展性

移行した結果データの鮮度が上がり、GCP基盤で基盤処理が動くようになったため、機械学習でのモデル生成時の精度向上や今後さらなるAI活用などの発展性が増えました。

費用

インフラ費用はBigQueryおよびGCP基盤にしたことで年間費用を約50%削減しました。また、固定費用で支払っていた移行前に対して、BigQuery・GCP基盤にしたことで今後さらなるコスト減も見込めます。

保守・運用コスト

以下の理由により、保守・運用コストが下がりました。

  • 環境分離により、本番影響を気にしながら開発作業をする必要がなくなった
  • リプレイスと処理の整理により、コード量を90%以上削ったため可読性が向上
  • オンプレ環境独特の保守・運用作業がなくなった
  • 拡張性が向上し、やりたかった事が続々とできるようになっている

想定していなかったメリット

解決したかった課題の他にも、いくつか移行メリットがあったのでご紹介します。

タイムトラベル

BigQueryには、タイムトラベルという過去7日間であればデータ復旧可能な機能があります。オンプレDWHの時は、夜間に毎日dumpを取る処理がありましたが、タイムトラベルの機能を使えば過去データは復旧可能と判断し廃止しました。この機能はデータ不備発生時の調査に非常に役に立ちます。またMAで利用しているデータ基盤のBigQueryテーブルについては、データ基盤チームが更に時をいい感じに戻す仕組みを社内で提供してくれており、こちらも調査で使わせてもらっています。時を遡るBigQueryに関するテックブログをデータ基盤チームが出していますので、興味のある方はこちらをご覧ください。

techblog.zozo.com

パーティション分割

BigQueryには、パーティション分割機能という機能もあります。パーティション項目を指定することでデータ量の大きいデータでもローコスト、ハイパフォーマンスでのクエリ実行を実現できます。オンプレDWHの時は、ある大きなテーブルで分散キーを指定してもクエリが劇的に遅延する事象が発生していました。先の通り情報が不足していたため原因究明には至りませんでした。事象解消のため、dailyのBigQueryへのデータ連携にデータを残しつつ夜間に該当の過去データをオンプレDWHから削除をする処理がありました。オンプレDWHから削除した過去データを全て蓄積してもこういったデータ量起因と思われる謎の遅延は発生せず、パーティション分割項目も有効に働いたため、該当テーブルの過去データ削除処理を廃止しました。

今後の展望

自動テスト・データチェックの強化

今回は自動テストの不足により、移行後に一定日数が経過した後でデータの不備を発見しました。データ不備は検知がなければ何も気付けません。後日各所からの連絡でじんわり気づくことになります。

恒久的にデータチェックやテストコードを充実し、検知を素早く、開発をより安全に効率よく進めるための改善を引き続き進めています。

配信作業の効率化

配信作業はGUIのジョブ・スケジューラを使ってビジネス部門が対応してくれていましたが、GUIによってポチポチできていた作業が、移行後にできなくなったため、配信作業の効率を急激に下げてしまいました。開発改善を重ねてなんとか移行前とほぼ同等の状態まで戻せましたが、移行前よりも拡張性が向上したため、現在はさらなる効率化に向けて改善を進めています。

リファクタリング

機能の必要有無を確認しながら1つ1つ実装を進めたので処理が冗長な状態で残っているため、より最適な設計を検討しつつリファクタリングを進めていきます。

スキーマ管理

移行作業を優先したためBigQueryのスキーマ管理は移行時にスコープから外しました。一部Terraformで管理されていますが、データを洗い替える処理の中で制約が外れてしまうケースもあり、今後最適な方法を検討しつつ進めていきます。

発展性の実現に向けたアプローチ

MAのデータを使った機械学習やAI活用がより正確にかつ利用しやすい状態になったり、GCP基盤になったことで出来ることが増えたため、今後の発展性の実現に向けたアプローチを進めていきます。

まとめ

以下、まとめです。これから同じようなチャレンジをする方の少しでもお役に立てれば幸いです。

  • 移行の経緯は分析と運用の効率化
  • 移行スコープはオンプレDWHの関わるオンプレ基盤全てが対象
  • ドキュメント、着手順、切り替え時の留意点などを考慮して作業を進行
  • 目的達成に加え、さまざまなメリットあり
  • テスト、運用効率化などについて今後の展望あり

記事は以上です。読んでいただきありがとうございました!

さいごに

MAでは一緒に働く仲間を募集中です。実は今回のリプレイスで、MAの募集要項に記載の利用技術から移行前の技術の記載がごっそりなくなりました。そんな話も踏まえて、MAに興味を持った方は、以下のリンクからぜひ閲覧・ご応募ください!

hrmos.co

hrmos.co

カテゴリー