書き手:@takegue (分析チーム)
Rettyのデータ活用の多くにはBigQueryが現在利用されており、その活用の方法についてこれまでこのブログでもいくつかとりあげさせていただきました。
engineer.retty.me そのほか分析チームの記事一覧
これらの記事はおかげさまで好評いただいております。いつもありがとうございます。 しかしながら、我々が初期からこのようにBigQueryを使い続けてきかというと、実はそうではありません。 事業の成長とともにデータ基盤を変化させてきた経緯があり、今の成果は過去のトライアンドエラーの賜物であり、数多くの苦労を背景にしてできあがっています。
ほんのつい最近まで、Rettyで構築されていたデータ基盤は表立って見える実態よりもかなり複雑なパイプラインで構成されていました(以降で触れますが、4種類のデータパイプラインが共存しているカオスな状態でした)。 この複雑さは、結果として運用上のリスクや不要なコストへ繋がっており、一部のコンポーネントは全体の性能のボトルネックとなるような状態をもたらしていました。 この問題は弊社が長年抱える頭の痛い問題でした。
直近の取り組みにより3ヶ月弱と短い期間で刷新を行うことで、無事解消することができました。
本記事では、これらの背景となる弊社でのデータ基盤に関する変遷について記述すると共に移行の際の問題をどのように乗り越えたかについていきます。
データ基盤の歴史
事業で利用するストレージに関する機能は性質上最も歴史的影響を残しやすいものです。依存が増えやすく、安定性が求められることから変更のコストが高いためです。
データ基盤ではより広範囲のデータを一手に取り扱うため、過去のサービスの状態も取り扱うため、年を重ねるごとにこの傾向がより強くなります。
弊サービスRettyの開始は2011年で、10年弱の歴史を持ちます。
今回の取り組みについてより解像度をあげるため、データ基盤の歴史について取り上げていきます。
以下少々長くなりますがお付き合いください。
黎明期: サービス当初〜2014年後半
サービス当初〜2014年後半までにおいては、データ基盤としての仕組みは特別意識して用意されていたわけではありませんでした。
当初の主だった分析目的は、サイトコンテンツの分析やSEOで、アクセス解析にはGoogle Analytics、サービスのコンテンツの開発分析にはAmazon RDSが利用されていました。
本番環境を複製したRDS環境に共存する形で開発環境が配置されており、機能開発をはじめとする分析/開発業務はこれらのRDS上で盛んに行われていました。
「RDS上にいろいろなデータがあると便利だよね」ということから、Google Analytics上のレポートがRDSへエクスポートされたり、収集したデータがRDS上に集められていくうちにこのRDSがデータ基盤としての役割を担っていった、という形です。
レポートは簡単なものであればスプレッドシート、プロジェクトの数値目標のモニタリングのためにはredashも利用がされてたようです。
またチームによっては自前のダッシュボードを用意していたこともあったようです。
このようにRetty初期のころから、数値みつつ開発を行う基本の体制が敷かれていました。
大規模集計可能な第2世代データ基盤: 2014年後半〜
2014年後半ごろまでGoogleAnalyticsが分析に主に使われていたようですが、集計済データによるユーザ行動のマクロ的な理解よりも、よりミクロな観点でのユーザ行動の分析を行いたいという需要が高まりました。
これに対してGoogleAnalyticsとRDSを使ったプラクティスでは機能面、性能面の両方で限界が感じられ、自前のログ基盤の開発をするに至りました。
そこでSaaS上にfluentdなどを使ってデータを転送し、データパイプラインを構築することでデータ基盤が構築されました。
これが第2世代データ基盤です。
この時のワークフローの管理自体もmakeとcronを利用した簡素なものでした。 また上記とセットで、ログ埋め込みをアプリケーションに簡単に埋め込む仕組みも構築され 現在に至るまでにサービスの大量のログを基盤上で扱えるようになりました。
この基盤が整備されたことで、サービス上のユーザ行動についてより解像度の高い形での分析の実施が可能となり、ユーザ理解やSEOのコンテンツ分析に役立てることができました。 RDSではできなかった大規模な集計作業がSaaS上で簡単に行えることもあり、この集計を利用した機能がアプリケーションに搭載され始めました。 RDSのデータ自体はこの基盤上に配置はされず、SaaS上の集計後のデータをRDSに転送し利用することでRDSのデータとの突合を行っていたようです。
このデータ基盤の活用が盛んになるにつれ分析利用の弊害が生まれはじめます。 SaaS上ではジョブキューシステムが採用されていました。これが詰まることでアプリケーション利用しているジョブの開始時間へ影響を与えることが問題になりはじめたのです。 大量の試行錯誤を主とする開発や分析のための操作が時にアプリケーションへ影響を与えることになることから、気をつけながら使う必要もあり使い勝手は良いものではありませんでした。 サービスの成長にともない取り扱うデータ規模が大きくにつれ、ジョブ単体のかかる時間も増えました。 またそれに伴う必要となる分散処理システムのエンジンに関するパラメータ調整もフラストレーションとなっていたようです。 このフラストレーションから試行錯誤のしやすいデータ基盤の必要性が高まりました。
BigQuery黎明期による第3世代データ基盤: 2016年前半〜
第2世代データ基盤の限界は2016年前半ごろに迎えました。 分析/開発のための試行錯誤をより迅速に行うために独立したサンドボックスの要求が高まった結果、導入されたのがBigQueryでした。 このデータ基盤の構築は前述のデータ基盤らからデータを転送することで実現されました。したがって分析開発用のRDSと先のSaaSの2つを依存先に持ちました。 加えて、RDSのデータを新たに直接BigQueryへエクスポートすることでより横断的かつ高速な分析が実現されました。 先のデータ基盤から用途の棲み分けができたこと、BigQueryのリソースで殴る衝撃的なパフォーマンスの良さも相まり、第2世代データ基盤での問題を解消することができました。
ストレスフリーな新しい基盤はBigQueryが素晴らしかったこともあり社内での利用も順調に増えていきました。 その反面、初代データ基盤, 第2世代データ基盤での開発ないし運用が過疎化していきました。 依然として、これらのデータ基盤への依存を抱えているにも関わらず、知見が多く集まるのは利用が頻繁にされるBigQueryのみです。
そうこうしているうちに時間経過と共に人の入れ替わりも進み、初代、第2世代データ基盤から第3世代データ基盤までのパイプラインは関心の空白地帯と化し、諸々のオーナーシップが浮いた状態に繋がります。 この状態は特に困りもので、ノウハウも失われているためトラブルが起きた際にどのような手順を持ってして臨むべきか、を最初から掘り起こす必要がありました。 今でこそ図示ができていますが、当初は全体像の把握自体も十分されていない状態でした。 データパイプラインは性質上、上流に位置するジョブの再実行を行う場合、下流の対する再実行操作も行う必要があります。 ゆえに、パイプラインの長さはそのままデータの到着時間に直結するため、時折発生するトラブル対応のの時間を長期化させる悪影響も目立つようになりました。
知見を得るためにはシステムを触る必要があるが、知見を持たずに触ると大問題に繋がる、そしてのその大問題の解決はとても時間がかかる、といった構造は開発に対する負のスパイラルを産み出し、他方でBigQuery上の利用はより進み複雑さが増す。全体としてみるとデータ基盤がかかえるリスク自体は大きくなっていきました。
刷新による第4世代データ基盤: 2017年初頭〜
BigQueryで構築されたデータ基盤は2017年初頭には社内での地位を十分に獲得していました。 しかしながら利用用途は増える一方で、利用者が個々の目的のために自由に利用していたこともありカオスさを極めていました。 ここに色々と耐えかねてBigQueryを中心としたデータパイプラインを構築しなそうというリアーキテクチャプロジェクトの動きが起こります。 第2世代データ基盤を経由せず新しいデータパイプライン/データウェアハウスを構築しなおそうよ、という取り組みです。 この時に分散型ワークフロージョブ管理システムとしてAirflowやk8sが導入されたり当時としてはモダンな技術が取りこまれました。
これにより、これまでカオスだったデータ基盤も終止符が打たれる…と思われたのですが、残念ながらこのデータ基盤への移行には至りませんでした。 その理由は、結果論ではありますが以下のような項目があげられそうです。
- データ基盤が開発ライフサイクルに馴染まない
- 必要水準を満たせていなかった
- データの到着時間が必要水準に達していなかった
- 新しいデータソースには新しいデータしかこないため、直後からの移行作業が進められなかった。
- 第3データ基盤で利用していたデータソースと互換性がなかった
- 移行作業の単純な不足
- 利用者側は移行するインセンティブも特になかった
- 移行に伴う集計誤差についても十分な検証はされていなかった
- 既存のデータソースについて積極的な移行がされなかった。
そして、現在に至る
といったところで、Rettyは4種類のデータ基盤を抱えることになりました。 筆者とのデータ基盤との本格的なお付き合いが始まったのはここからになります。
学ぶべきことは何か?
ここまでで長い歴史的な変遷を辿ってきましたが、改めて得られる学びについて考えてみましょう。
基盤、という名の共用リソースの罠
データ基盤、という言葉は今でこそよく聞かれる言葉となりましたがここにひとつ大きな罠があります。 第2世代データ基盤での事例を振り返ると、アプリケーションの機能として安定的に実行したいジョブと多くの試行錯誤を旨とする分析開発用のジョブを 意図的ではないにしろ同じキュー上で共存してしまったことで問題がおきています。 分けるべきものをまとめてしまった、誤った共用化による問題です。
ここから学ぶことは基盤の名をつくものの多くのものから依存されることが前提で構築されますが、それらが誤った共用化になっていないかを常に意識するべきということでしょう。 共用化が必要であれば、多少の不便を強いてでも標準をもうけ基盤開発の観点から依存に対する取り扱いを統一的に取り扱えるようにするのが好ましいでしょう。 一般に多数からの依存を持つで後から標準を制定し、それを遵守させることは多大な労力を伴います。これはWebの標準制定にまつわる歴史を見てもこれは明らかです。 これは基盤開発を推進する上で悩ましい問題です。なぜなら基盤が使われないうちに利用を制限するルールはないほうが利用推進に都合が良いためです。最初は簡単さや便利さが好ましいはずです。
もしあなたが何かしらの基盤を取りあつかっており、推進する立場にいる場合この問題について慎重に考える必要があります。 言い換えると規格や標準化に対する想像が働かない程度に十分な知識や経験がない場合、基盤を開発を目的とすることを可能な限り避けた方が賢明でしょう。 基盤という響きは効率化という甘美な香りは開発者を沼へと誘います。その欲求に抗いつつも時に愚直さを優先することが時に正解になることもあります。
困難は分割せよ、というプラクティス
第4世代データ基盤の失敗の一つは、全てを一度に置き換えようとしたことにあると考えられます。 解くべき問題を大きくしすぎたため、ゴールにおける重要なステップである移行作業がその計画から抜け落ちてしまいした。 結果として新旧のデータ基盤がどちらも残り続けてしまった、といった負担を大きくする結果をもたらしています。 リアーキテクチャでの典型的失敗です。
この問題に対し、古くから伝わる有用なプラクティスには「困難は分割せよ(Divide and Conquer)」があります。 「データ基盤の刷新」という大きな問題に取り組むのではなく、例えば、分割して「RDS系の移行」、「イベントログ系の移行」...といったような分割が考えられそうです。既存のシステムをリファクタリングし、再利用することも十分に検討すべきだったでしょう。 すべてを一度に移行する必要はありません。長期化するものほどサンクコストもあり失敗の判断はつけづらくなります。 後戻りや中断の手段が用意できていなければなおさらです。100歩進んで100歩戻る大博打の選択よりも、50歩しか進めないが最悪でも10歩しか戻らない、といった選択肢が用意できるようにできるとよいでしょう。
事業会社におけるデータ基盤、というサービスの性質
一般に、ストレージが抱える負債というものはサービス運営で特に重くなりやすい傾向にあります。 例えば、アプリケーション開発においてDBが抱える負債は返済しようにも苦労が大きく 技術的な難易度が高いことは身に覚えがある方も多いと思います。多数のコードから依存されている対象を壊さず扱うことは、爆弾処理のような難しさを連想させます。 データベースがサービスに関する現在の状態をあつかうサービスであるのに対して、データ基盤はサービスに関する過去と現在の状態を扱うサービスです。扱う対象の複雑さはデータベースのそれより増し、苦労も大きくなる傾向にあります。
またデータ基盤は数あるサービスの依存関係の中では最も下流に位置するサービスです。 下流に位置するということは上流側の影響を須く受けるということです。これは基盤自体の不安定さを招きます。 上流側となるデータベースやコードベースは事業開発に伴い変更されることが多い代物です。データ基盤はそれへの依存であるため、相対的に不安定になります。それにもかかわらず、残念なことに、アプリーケション開発に費やされるリソースよりもデータ基盤開発へのリソースが豊富になることは基本ありません。データ基盤自身の開発/運用よりも利活用へのリソースの方が常に多く、これは避けられない制約です。 これらをデータ基盤を開発/運用していく際には、これらの性質を事前に理解し設計に組み込んでおくことは困難を避ける手助けになります。 その意味では、開発・運用コストを下げることができるSaaSの利用は良い選択肢のひとつです。
関心の空洞による知見の消失
データ基盤の苦しみが増えたターニングポイントのひとつは、BigQueryでのデータ基盤が作られた際に異なるSaaSを跨いだことによる 旧データ基盤の空洞化は問題のひとつでしょう。 第2世代データ基盤→第3世代データ基盤というSaaSを跨いだ依存関係が構築されたのち、 第3世代データ基盤が使われるようになり、急速に第2世代データ基盤に対する知見が失われ始めました。 触らなぬ神に祟りなし、ということで空洞化したシステムは心理的に忌避する結果を招きました。
サービスの価値の中核となる技術に対して知見が育ちやすいように、知見の多さというものは、その部分への関心の高さに関係があります。 100の価値を出すために10のコンポーネントで構成されるシステムよりも、70の価値しか出せないが、3つのコンポーネントで済むシステムである方がこの関心の高さを集めるのには有利です。コンポーネントが多いほど関心が分散し、知見が溜めづらく属人化やサイロ化を招くことになるためです。
現在のデータ基盤におけるトレンドとして、問合せのクエリだけでなくデータ処理(e.g Cloud DataFlow)も同じようにSQLで記述するというUnified Modelのパラダイムが歓迎されはじめています。この背景には高機能であることよりも簡便さが求められたが故といえるでしょう。
移行を設計する
以上の学びをもってして、この歴史的経緯を文化遺産と称え学びの象徴として共生する、ということもできますが
いち開発者としてその選択は退屈なものですし、長期的な金銭的コストとしても安い選択肢ではありません。
敬意ははらいつつも余計な苦労をもたらす点は早期に取り除くことが肝要です。
以下の3つをステートメントとして、移行作業を執り行うことにしました。
- 精巧さよりも簡便さを優先する
- 関心の盲点がなくす設計にする
- 安全かつ迅速に移行する
次の図は移行後のアーキテクチャ図です。
「おや、どこかでこれを見たな...」という方もいるかもしれません。これは第2世代データ基盤をBigQueryで再配置したような単純なアーキテクチャです。 このシステムへの移行について見ていきましょう。
関心の盲点を設計でなくす
まず大事な点として過去の反省を活かし、中長期的に見て関心の盲点が生まれづらいように設計へ観点を取り入れています。 データ基盤開発者と分析者の関心が重なるところに変更可能性が高いものを配置することで実現しています。
これはBigQuery上に未加工のデータを配置するStaging Areaを配置することで実現します。 そしてStaging Areaを境として左を転送システム、右をDWHシステムとして役割に境界を引くことでそれぞれのシステムの役割を単純化しています。 転送システムでは加工処理を担わず、それまで行っていた加工操作をすべてBigQuery上に寄せDWHシステムの責務とするELT型アーキテクチャとなります。
この方針はDWH上に余分にストレージを配置するコスト面で不利になるのと、バッチ処理が主体的になるためいくつかの不便を享受することになりますが代わりに次の利点があります。
- 利用者/開発者にとって転送システムの透過的な取り扱いが可能に
- SQLが十分に取り扱える分析者であればデータパイプラインを全て取り扱うことができます
- DWHシステムにおいてデータ基盤開発者が担当すべき領域が減ります
- 移行作業に最も時間がかかるBigQueryのへの転送部分の構築が単純化されます
- 加工作業が単一のSaaSに閉じるため恩恵をSaaSを十分に受けやすくなります。システムを横断する際のインピーダンスマッチの影響を最小にできます。
またRettyの事情を鑑みた場合に、分析者の数はデータ基盤開発者よりも多いためこの設計の方が持続可能性が高くできるだろうという判断もあります。 分析者がDWHシステムをより自律的に変更することも将来的に期待できまし、その際にはデータエンジニアの必要性を薄くすることができます。またデータの処理系が複雑化すれば別途切り出せば良いですが、その際にはCloud DataflowなどのSQL中心のUnified modelを採用することで資産の再利用も可能です。
安全かつ迅速に移行する、ための設計
今回の移行作業は複雑化したデータパイプラインを単純化するため、BigQuery上で利用しているデータソース自身の差し替えが必要となりました。 この変更はデータ基盤上で動きつづける数十から数百のジョブ、またはデータ基盤を利用したアプリケーション、ダッシュボード、現在進行している分析または過去に組まれた予算のための集計など非常に広く影響します。 移行のため新旧のシステムが並列稼働する期間を短くするするための工夫も必要です。 移行作業が中途半端になり、過去を繰り返し5つのDWHシステムを抱え続けるのは最も避けたいのシナリオのひとつでしょう。 加えて移行作業に存在する不確実性もあります。現行のデータ基盤は知見が薄まり続けた中で逐次的に開発されたことから、全体として完璧とは言い切れません。 データパイプラインを構築しなおすことで集計の誤差の生じさせる不安があります。
この困難を極める課題を乗り越えて安全かつ迅速に移行のためには物事をまず簡単化する必要があります。 移行作業のサービスレベル目標(SLO)とサービスレベル指標(SLI)を定義し、設置することにしました。 ステークホルダーと相談しSLOを設置することで期待値が調整できます。これはプロジェクト推進に対する安心へつながります。 またSLIを設置することで作業の進行具合の開示と試行錯誤が簡単になるため移行作業の安全につなげることができます。
ステークホルダーであるアナリストやプロダクトオーナーと相談し、影響のある集計項目を数百種類を洗い出し、それらについての取り決めを行いました。 そして、これらの項目についてSLIの計測を容易にするために集計項目の規格化を行います。 規格化された集計項目とは、以下のようなSQLから得られる集計テーブルです(一般にファクトテーブルと呼ばれます)。
数百ある集計項目ですがものによっては「セグメントの切り方の違いだけが集計方法の違い」といったように、ある集計項目が他の集計項目と関連することが多くあります。 これは言い換えると、集計テーブルから複数の特定の集計テーブルが再計算で生成できるような最小粒度のレコードをもつ集計テーブルが定義できます(グレインテーブルと呼ばれます)。 うまくする定義ことで数百ある集計項目に対するSLIの計測の複雑性を大きく下げることが可能です。
集計項目の規格化ができれば、移行のために次のような品質チェック用の集計テーブルと自動的に用意することができます。これによりSLIを元にした迅速な試行錯誤が可能になります。
指標名 | segments 時間, ユーザ, コンテンツ… |
指標値 (legacy source) |
指標値 (new source) |
誤差指標 誤差, 相対誤差, 分散, … |
---|---|---|---|---|
レコード数 | time=2020-05-01,type=A,… | |||
PV数 | ||||
… |
手順についてまとめると以下の通りです。 これらの手順の多くは自動化可能であるため、CIなど用意すれば迅速かつ安全に試行錯誤に繰り返すことができます。
- 既存要件の規格化された集計ビューの用意 (参照は古いデータソース)
- 移行予定となる集計ビューの用意(SQLはほぼ一致であるが同じだが互換性のある新しいデータソースを参照)
- 1と2の比較用のテーブルである上記表の生成
移行を実行する
ここまでで移行のための設計が整えれられました。あとは順次移行作業を粛々と進めていくだけです。 その際に直面したいくつかの問題と対処方法についてまとめていきます。
多くの依存を抱えているテーブルをどうあつかうか?
データ基盤の移行作業は、影響が広いため段階的なリリースの手段を用意することは慣用です。 BigQuery上ですでに構築されているデータ基盤上の依存関係は複雑で、コード管理下にないアドホックなSQL、ものによっては数十のSQLやビューからの依存されている物理テーブルも珍しくありません。 物理テーブルを論理テーブル(以下ビュー)に差し替えることで、より安全に移行作業を進めやすくすることができます。
手順としては、
- 対象となる物理テーブルをリネームし、
select * from renamed_tgt_table
を実体としたスキーマが一致するビューに差し替える - SLA用の比較をこのタイミングで検証を行い、有効であることを確認する
- 新しいデータソースで構築したスキーマが一致するビューを用意し、差し替えて再度検証を行う。
これによりビューを部分的に差し替えることができ、問題があればすぐに戻すロールバックも容易になります。
Airflowとk8sによるオートスケールする分散ジョブシステム
移行作業を短い期間で終えるためには、これまで配置されていなかった数十TB弱規模のデータをBigQueryに配置する必要があります。 1日数時間程度要していたジョブをそのまま逐次実行するだけでは間に合わず並列度を高め、短縮する必要があります。
この問題については、Airflowとk8sが役に立ちました。(詳細はhttps://airflow.apache.org/docs/stable/kubernetes.html を参照ください) Airflowとk8sをうまく取り扱うことで、必要リソースに対してオンデマンドにオートスケール可能な分散ジョブ処理システムが構築できます。 これにより並列実行が用意となりロードの高速化を行うことができました。
関与するコンポーネント/サービス群の改修&アップグレード
移行作業には、転送システム上でサービスで実装されているのログのフォワーダといった転送システム上のコンポーネントの改修作業も必要としました。 サービスが大規模化するにつれて、複数のアプリケーションにてそれぞれログを取り扱うことは珍しくないとは思いますが、それぞれぞれのアプリケーションでのコンポーネントの状態がまちまちで、サービスが動き始めてからアップグレード作業が一切行われていないものや不自然に歪な構成となっているもの、CIがしばらく緑を返していないものもありました。
データパイプライン上に存在する、これらコンポーネントを地道にアップデートし、CI/CDなども可能なら整備しつつ、移行作業が万全の状態で進められるようにしていきます。 結局のところ今回の基盤の移行作業について最も時間を要したのがこの部分でしたが これらに対する対抗手段は、地味にひとつひとつ解消する以外になく根気よく続けていきました。
結果
そんなこんなで移行作業を行い、3ヶ月弱程度での移行作業を終えることができました。 移行前後で、目に見える成果を取りまとめると次のような結果が得られました。
- 主要な集計項目において誤差+1%以内での速やかな完全移行の達成
- データ基盤にかかっていた費用の70%弱減
- データ到着時間、MTTRの大幅な改善
- バックフィル操作について3〜5hかかっていた部分を10min程度に短縮
移行前で抱えていた苦労がそのまま解消された形です。 データ基盤を構成するコンポーネント数を減らせたこと、開発環境の改善がおこたえたことで運用面においても大きな改善ができました。 パフォーマンス改善の多くはBigQueryの素晴らしい性能によるものです。その素晴らしさに改めて感謝です。
まとめ
この記事ではデータ基盤の歴史と移行について書きました。 Rettyのデータ基盤自体は決して固定化されたものではなく事業の遷移と共に段階的に変化してきた経緯があります。 それに伴う歴史的経緯がこれまで大きくのしかかっていましたが、今回の移行作業でこれまで抱えていたそれらを精算することができました。 性能、費用や運用でのいくつか目覚ましい成果を得ることができました。
スコープが肥大化しがちなデータ基盤開発においても、その基礎となるサービス開発とそこまで変わるものではありません。 そのポイントとして「変化させたいタイミングで変化させられること」かにあると思います。 これまでの状態は扱っているコンポーネントに振り回され続けている状態でしたが、今回の移行はその余力づくりに寄与した取り組みでした。 今回記載したアーキテクチャも決して固定的なものではありません。 今後とも事業やトレンドにあわせてデータ基盤の変化が起きることは予想に難くなく、BigQueryをはじめとするSaaSはより新しい機能が開発されることになります。 これらの変化に追従ないしは振り回されないための仕組み作りが大事です。 おりにふれ、変化していくデータ基盤についてまたお届けできればと思います。
最後に、この資料が今後データ基盤に携わる人々のお力になれば幸いです。