Architecture Evolution in Repro

Architecture Evolution in Repro

railsdm2019

A5e5ee2fb9e4ce3c728ed9e3ef6e916f?s=128

Tomohiro Hashidate

March 23, 2019
Tweet

Transcript

  1. Architecture Evolution in Repro @joker1007 (Repro inc. CTO)

  2. ⾃⼰紹介 @joker1007 Repro inc. CTO Asakusa.rb RubyKaigi 2019 Speaker 最近は主にデータエンジニアっぽい仕事

  3. Repro というサービス スマホアプリ・Web サービス向けのアナリティクス ユーザ属性や利⽤履歴を元にしたセグメンテーション セグメンテーション対象に対するダイレクトマーケティング セグメンテーション対象に対する広告出稿 こういった機能をサービスとして提供している。

  4. Retention Analytics

  5. Funnel Analytics

  6. User Segmentation

  7. サービスのスケール 総デバイス数 数億超 ⼀度のプッシュ配信数が最⼤で1000 万〜2000 万デバイス ⽉間で送信しているプッシュメッセージの数が約40 億超 つまり、数千万のユーザの数⽇分の履歴やプロフィール情報を任意に組み合わせて、 必要とするユーザーの集合を短時間で抽出しなければならない。

    それがRepro のユーザーセグメンテーション。
  8. 過去に戻って2016 年半ば 数万ユーザの集計とセグメンテーションの時代

  9. RDB の限界 MySQL でリクエスト時に集計して結果をRedis にキャッシュ。 ⾃分が⼊った当時で既に初回表⽰に10 秒以上かかるページがあった。

  10. 中間集計テーブルとバッチ化 とりあえず突貫でMySQL 上に中間集計テーブルを作る。 ⼀部の集計をバッチ化するが、データ構造上アプリ毎にループで実⾏していた。

  11. ナイーブなバッチの問題点 顧客が増えれば線形で実⾏時間が伸び即破綻する。 顧客が増えてもスケールでき、かつ顧客毎に集計更新に差が⽣じない様にする必要が ある。 安易にバッチ化するとこうなりがち。

  12. fluentd & embulk & Bigquery Bigquery の採⽤ データ転送のためにfluentd とembulk を利⽤

    それぞれのプラグインに何回かPR 出してたらコミット権を獲得
  13. Bigquery の採⽤理由 スキーマ設計を頑張りたくない 分散キーとかソートキーとか 異常なコストパフォーマンス まともなSQL に対応

  14. fluentd 運⽤時の注意点 データ転送量が多い時の注意点 ブロッキングで詰まらない様にflush スレッド数を調整する ⼗分なファイルストレージを⽤意する 特にBigquery はAPI が良く死ぬ require_ack_response

    とsecondary output は基本的に必須 でないとデータロストする secondary でエラーファイルをS3 に書き出すのは割と⼤丈夫 <label @ERROR> によるエラーハンドルを設定 どのレイヤーでどこまでデータが貯まって、 どこまでの到達が保証できるのかを認識しておく事が重要。
  15. Bigquery 採⽤後の構造

  16. Bigquery で解決できたこと 集計処理がめっちゃスケールする様になった 当時から現在まででデータ量が数⼗倍ぐらいになったが、集計時間は⼤きく 変化していない 全ての顧客に同時に集計結果を出せる様になった ただ、SQL 構築するのに、かなりの時間を費した。 特にFunnel Analytics

    は超⾟かった。 ( ハードな集計SQL に興味がある⼈は後で直接質問を)
  17. Bigquery では⾟いこと ユーザーが任意のタイミングで任意の条件でセグメンテーションし、短時間で結 果を返すのが厳しい 即時クエリの同時実⾏上限が存在する クラウドとリージョンを跨ぐデータ転送 Bigquery はクエリ課⾦ 利⽤されればされる程、Repro 側が損することになる

    当時は顧客毎にクエリ対象を分けられなかった 現在はclustering key で多少カバーできそう しばらくは持つが、顧客の数が増えてくると破綻する。 ( また同じ問題…… 。)
  18. Rukawa の開発 Bigquery 採⽤に伴いバッチの数が激増 依存関係や並列実⾏可能かどうかを上⼿く調整する必要が出てきた ワークフローエンジンrukawa を開発 以前の発表資料 Ruby 製のシンプルなワークフローエンジンRukawa

    の紹介 ワークフローエンジンRukawa と実装のサボり⽅
  19. ユーザーセグメンテーションの裏側 各条件をツリーとして表現し、Operator ノードで繋ぐ 各ツリーのノードはSQL として解決可能になっている ツリーを再帰処理しながらOperator がJOIN やIN 句を使ってクエリを結合する 最終的に出⼒されたクエリをクエリエンジンに投げる

    これらはRails のモデルとして表現されており、ERB を利⽤してSQL を構築している。 つまり、モデルの中にERB のテンプレートがある
  20. SELECT DISTINCT user_id FROM filtered_custom_event_histories WHERE <%= event_property_where_clause(and_properties, and_not_properties) %>

    こんな感じに解決可能なものを組み合わせる。
  21. セグメンテーションツリーのイメージ SQL に解決しながらJOIN で折り畳んで、集合を組み合わせていく。

  22. この辺りで⼤半の実⾏基盤をコンテナ化 過去に喋ったり書いたりした記事があるのでそちらを参照。 production 環境でRails アプリをdocker コンテナとしてECS で運⽤するために考え たこと 開発しやすいRails on

    Docker 環境の作り⽅ サクっとAmazon ECS のクラスタを構築するためのterraform の設定 Docker コンテナ上でのassets precompile の扱い 2017 Rails アプリをECS で本番運⽤するためのStep by Step Docker 時代の分散RSpec 環境の作り⽅ 記事には書いてないがEmbulk on Fargate とかも ( これも詳細は質問や懇親会で)
  23. Presto on EMR を採⽤ クエリ数が増えてもコストが線形に増えない様に 実際負荷が上がればコストは上がるけど AWS で完結する様にして、クエリレイテンシを下げ、アドホッククエリに対応す る MySQL

    やAurora 、その他のデータストアに接続できるので、それらを組み合わせ ることができる
  24. Presto とは Facebook が開発した分散SQL クエリエンジン。 Presto ⾃体はデータストアを持っていない。 コーディネータがSQL を解釈し、様々なデータストアに対するコネクタがデータスト アに合わせたリクエストに変換し並列でクエリを⾏う。

    最も良く使うのはhive connector で、Apache Hive のメタデータを利⽤してHDFS やS3 に並列でアクセスし⾼速にSQL を利⽤したSELECT が可能。 複数のデータストアのテーブルをJOIN することもできる。
  25. Hive とEmbulk によるデータ変換 Bigquery で集計したデータをEmbulk でS3 に転送 fluentd でS3 に蓄積したデータと合わせてHive

    でParquet に変換 Presto でクエリして柔軟な条件によるセグメンテーションを実現
  26. Apache Parquet とは カラムナー( 列指向) フォーマットの⼀つ。 Google がBigquery ⽤に開発したDremel というフォーマットの論⽂を元にしてい

    る。 似たフォーマットとしてORC がある。
  27. カラムナ フォ マットのイメ ジ

  28. なぜ列指向なのか ⼤量のデータを抽出したり集計したりする時は、⾏ではなく列単位でデータを持 っていた⽅が効率的に扱える。 圧縮効率とか、特定カラムを全取得する場合等に有効

  29. Presto 採⽤後の構造

  30. Presto でも解決できなかったこと Parquet 変換にバッチが必要 抽出条件に引っかかる様になるまでに時間がかかる 更新が発⽣するデータの扱いが⾯倒 基本追記オンリーなので重複排除等が必要 MySQL では読み書きのスケーラビリティが厳しい Presto

    で⼤量にデータ取得するとクソ遅い
  31. Cassandra を採⽤する DynamoDB の論⽂を参考にしているNoSQL で完全な⾮中央集権構造が特徴。 Presto で元々サポートしている 書き込みスケールしやすい ⼤量に読み込むのは得意ではない 台数がある程度あればMySQL

    よりはマシ 実験してみてしばらく持つだろうと判断
  32. Cassandra 採⽤後の構造

  33. Presto & Cassandra & S3 リアルタイムで更新したいデータをワーカーで直接Cassandra に書き込む 集計が必要なデータはBigquery で集計, S3

    に転送しParquet に変換する Presto でCassandra のデータとParquet on S3 のデータを組み合わせる ほとんどの規模の顧客のデータは1 分以内で返答可能 数百万を越える規模のユーザ数でも数分以内に。
  34. Cassandra でも解決できなかったこと 余りにもデータ量が多いと読み込みクエリ負荷に耐えられない そのため⼀部のデータはリアルタイムに反映したいが対応できていない 読み込み時のCPU 負荷が⾼い コストとスケールのバランスを⾒極める必要がある

  35. 未来のユーザーセグメンテーション Apache Kafka を導⼊ データ取得効率を上げるためのクエリ最適化 Cassandra -> Apache Kudu? Apache

    Kudu ⾼速なデータの挿⼊・更新と列指向の参照を組み合わせた分散DB 最近、Presto も公式サポートした。熱い。
  36. 妄想上の構造

  37. その他の課題 マイクロサービス化 サービスディスカバリ スキーマ管理 秘匿情報管理V2 ⾊々とやらねばならないことが。

  38. こういう仕事がしてみたいという⽅ 絶賛募集中です!! https://www.wantedly.com/projects/102039 https://www.wantedly.com/projects/44097