Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

『じゃらん』『ホットペッパーグルメ』を支えるクラウド・データ基盤

4 268 vues

Publié le

2017年6月14日に開催されたGoogle Cloud Next '17 in Tokyoにおける発表資料です。
弊社サービス横断で活用されているクラウド・データ基盤であるCETについて解説しました。

Publié dans : Ingénierie
  • Soyez le premier à commenter

『じゃらん』『ホットペッパーグルメ』を支えるクラウド・データ基盤

  1. 1. 『じゃらん』『ホットペッパー グルメ』を支えるクラウド・ データ基盤
  2. 2. 目次 ● 弊社事業の紹介 ● Capture EveryThing (CET) の取り組み ● API による分析結果の提供 ● リアルタイム処理システム ● Wrap Up
  3. 3. 自己紹介 ● 堀澤健太 ○ Twitter : @horiken4 ● 略歴 ○ 2011 年 スマートフォン向けゲーム開発会社 ■ 開発, マネジメント, 採用, R&D ○ 2016 年 株式会社 リクルート ライフスタイル ■ CET アプリケーションエンジニア リーダー
  4. 4. 弊社事業の紹介
  5. 5. リクルートのビジネスモデル <価値提供> 人生や生活の中で意 思決定においてその 人が必要とする情報 を提供 <価値提供> ユーザとの出会いの 機会や最終的なマッ チングを創出
  6. 6. リクルートライフスタイルのサービス概要
  7. 7. Capture  EveryThing の取り組み
  8. 8. Capture EveryThing ● サービス横断でリアルタイムにデータを収集 ○ 約 300GB /日 ● リアルタイムデータ分析に必要な処理を 一気通貫で実施 ● 分析結果を WebAPI として各サービスへ提供
  9. 9. チーム体制 ● エンジニア, データサイエンティスト, ビジネス系メンバで構 成 ● チームを跨がないため高速なイテレーションが可能 ● スキルのオーバーラップ ● 専門領域以外も担当 ○ データサイエンティストがインフラ構築 ○ エンジニアが分析
  10. 10. アーキテクチャ ● 黎明期は AWS を利用 ● 現在は GCP と AWS のマルチクラウド構成 ○ GCP の割合が大きい ● 同等の性能でコストを安く抑えることが可能 ○ GCP を利用し始めたきっかけ
  11. 11. AWS Log Aggregator Visualize (short period) Web Beacon Real-time Processing Our Service Visualize (long period) API Machine Learning アーキテクチャ Re:dash Rundeck Kibana elastic search nginx fluentd
  12. 12. API による 分析結果の提供
  13. 13. API ● 分析結果を API として各サービスに提供 ○ 機械学習による予測の結果 ○ レコメンデーション ● 基本的に Key に対する Value を返せば十分 ○ リクエストのたびに予測はしない
  14. 14. API US Region Our Service Asia Region アーキテクチャ Cloud Load Balancing API Container Engine Asia API Container Engine US Cloud Bigtable API Data Loader Worker Compute Engine Real-time Processing Pipeline Cloud Dataflow
  15. 15. API Data Loader ● API で提供するデータを Bigtable へ反映 ○ S3 へのファイル配置イベントを SQS へ流す ○ Worker が Receive して Bigtable へ書き込む
  16. 16. API Data Loader の利用ケース ● 他チームの API 利用者 ● 各種バッチ ● 最大数千万行の Bigtable への Put オペレーション
  17. 17. API サーバ ● Scalatra ベース ● GET のみ ○ リクエストパスに Key を含める ○ Key で Bigtable を引き Value を JSON で返す
  18. 18. API サーバ ● 列ファミリの TTL は厳密ではない ○ Bigtable の GC のタイミングで実際に削除 ○ Cell の Timestamp を参照し Expire を管理
  19. 19. Pod の終了時 ● Pod が SIGTERM を受信 ● API サーバが(デフォルト)で 30 秒後に終了
  20. 20. Graceful Shutdown ● Pod の readinessProve と terminationGracePeriodSeconds を設定 ● SIGTERM 受信後 readinessProveに対して 500 を返す ○ readinessProve が失敗する ● 新規リクエストはルーティングされなくなる ● terminationGracePeriodSeconds 秒後に SIGKILL ● Pod が終了
  21. 21. Graceful Shutdown ● CMD を bash -c の exec 形式にする ○ 環境変数を展開して引数に渡すことが可能 ○ シグナルを子プロセスへ伝搬
  22. 22. GKE と GCE を組み合わせて利用 ● GKE マルチゾーン クラスタ ● Instance Group のオートスケーラ ● Instance Group のオートヒーラ
  23. 23. Pod 数は固定 ● HPA で Pod が増減するタイミングは必ずしも CPU 使用率が増加するタイミングではない ● リソース不足でスケジューリングに失敗する Pod が発生 ● HPA は固定し必要な Node を用意
  24. 24. 理想のスケールアウト ● 理想は Pod 数が増減したらノード数が増減 ● リソース不足による Pod のスケジューリングが失敗 ○ その時に Node Pool がスケール
  25. 25. GKE Cluster Autoscaler ● リソース不足によりスケジューリングを待たされている Pod を監視 ● そのような Pod が発生した場合 Node Pool を大きく ● Node のリソースが十分使用されてなければ小さく
  26. 26. オートヒーリング ● http ヘルスチェックと Instance Group の Auto Healing を設定 ● kube-proxy により適切な Pod へルーティング ○ 実際に Unhealthy なのは別 VM かもしれない ○ Pod が Unhealthy なだけかもしれない
  27. 27. Node Auto-Repair ● Node のヘルスステータスをチェック ● 連続してなにも報告しない or NotReady だと再作成
  28. 28. 負荷試験 ● 性能劣化, ボトルネックの確認 ● 2つの GKE クラスタを作成 ○ Loader と API ○ Preemptible VM を利用 ● GKE クラスタ, k8s リソースの作成, 削除が軽快 ○ CI にも組み込みやすい
  29. 29. Loader と API ● Locust で負荷試験シナリオを作成 ● Job で Loader の Pod をデプロイ ○ Pod の再作成を防ぐ ■ locust … || exit 0 ● Deployment で API の Pod をデプロイ ○ Service は type: LoadBalancer
  30. 30. 複数の負荷試験 ● CI では同時に複数の負荷試験をしたい ○ API の Service の externalIPs は固定しない ○ 動的に API の IP アドレスを変更したい ● 変更可能にするため sed を挟む ■ cat job.yml | sed -e “s/__IP__/${IP}/g” | kubectl create -f -
  31. 31. ボトルネックの調査 ● VisualVM を利用 ○ JMX のポートに接続する必要あり ○ Service を作成する必要なし ● kubectl port-forward <pod-name> <jmx-port> ○ VisualVM で localhost:<jmx-port> に接続
  32. 32. リアルタイム 処理システム
  33. 33. 概要 ● サービス側からのリアルタイムなログを集計 ○ 約1万 msg/s ● リアルタイムに結果を API に反映
  34. 34. ユースケース ● ページ閲覧 UU 数集計 ● 最新予約日時抽出 ● リアルタイムユーザ属性推定 ○ 実サービスへの導入は未実施
  35. 35. Real-time processing Our Service アーキテクチャ Pipeline Cloud Dataflow Cloud Pub/Sub Temporary Table Cloud Bigtable API Table Cloud Bigtable Model Cloud Storage Log Aggregator
  36. 36. ページ閲覧 UU 数の集計 ● 30 秒ごとに 30 分間の UU 数をページごとに集計 ● ウィンドウが重複するのでスライディングタイムウィンドウ を利用
  37. 37. SlidingWindows の問題点 ● SDK 標準のスライディングタイムウィンドウ実装 ● 30 分未満のウィンドウを排出してしまう 30 sec 30 min ・・・
  38. 38. NonMergingWindowFn を 継承し assignWindows を Override する ウィンドウの開始時刻<パ イプライン開始時刻なウィ ンドウには要素をアサイン しない for (long start = lastStart; start > timestamp.minus(size).getMillis(); start -= period.getMillis()) { if (start < firstWindowStartBoundary.getMillis()) { break; } windows.add( new IntervalWindow(new Instant(start), size)); } 初期のウィンドウを破棄
  39. 39. Bigtable の Write 変換 ● SDK 標準の CloudBigtableIO ● 内部では ParDo 変換で BufferedMutator を利用 ○ 並列で Bigtable へ書込み
  40. 40. Bigtable の Write 変換 ● 書込みスループットが大きすぎる ○ Bigtable クラスタの理論限界値 50MB/sec ○ パイプライン 25MB/sec ● 複数のパイプラインを同時実行できない
  41. 41. Combine 変換を利用 extractOutput はシングル スレッド シンクなので null を返す public Void extractOutput(List<Mutation> accum) { BufferedMutator mutator = getBufferedMutator() mutator.mutate(accum); mutator.flush(); return null; } Write 変換のスロットリング
  42. 42. 最新予約日時の抽出 ● 予約ログを Pull するたびに予約日時をパース, Put オペ レーションを実行 ● 集計する必要はないのでグローバルウィンドウを利用
  43. 43. 最新予約日時の抽出 ● 予約ログの到達順序はログの発生時刻順ではない ○ Subscription からの Pull 順序は保証されない ○ ログの遅延によって古い予約ログが最近到達するか もしれない
  44. 44. 予約時刻を Put オペレー ションのタイムスタンプに設 定 タイムスタンプが新しい場 合にのみ Cell 更新 public void processElement(ProcessContext c) throws Exception { KV<String, DateTime> e = c.element(); Put put = new Put(Bytes.toBytes(e.getKey()), e.getValue().getMillis()) .addColumn( BIGTABLE_COLUMN_FAMILY, BIGTABLE_COLUMN_QUALIFIER, Bytes.toBytes(""" + e.getValue().toString(DateTimeFormat .forPattern("yyyy-MM-dd'T'HH:mm:ssZZ") .withZone(DateTimeZone.forID("Asia/Tokyo"))) + """)); c.output(put); } 古い時刻での更新を防ぐ
  45. 45. ユーザ属性推定 ● 直近数件のページ閲覧ログと検索ログから推定 ● アイテムの特徴量の平均値が推定値 ○ 推定処理は ParDo で実行 ○ 直近数件のログを保持するため Bigtable を利用
  46. 46. ユーザ属性推定 ● 書き込みのバッファリングが効くように固定時間ウィンドウ を採用 ○ ウィンドウごとに BufferedMutator で書込み ● 特徴量は更新を容易にするため GCS に配置 ○ 有限 PCollection ○ 推定の ParDo へ副入力
  47. 47. 複数の検収環境 ● 弊社サービスには複数の検収環境が存在 ● 検収環境ごとに異なる Topic にログを Publish ● 複数の Subscription から Read 変換し 無限 PCollection を作成
  48. 48. Flatten 後の副入力あり ParDo 変換 ● エラーが発生してパイプラインが実行されない ○ GetData failed: status: APPLICATION_ERROR(3): Computation F64does not have state family S1 for value read
  49. 49. 変換の順番を入れ替える ● 副入力 ParDo と Flatten の順番を入れ替えて回避 ○ 複合変換は PCollectionList を受け取り PCollectionList を返す ○ Put オペレーションを作成する ParDo 直後で Flatten
  50. 50. パイプラインの自動スケーリング ● スケールする時にパイプラインが一時的に詰まる ○ Unacknowledged Messages が増加 ● 自動スケーリングは無効化
  51. 51. パイプラインの監視 ● Unacknowledged Messages の監視 ● Bigtable への書込み回数を監視 ○ 書き込み時にログを出力 ○ Stackdriver logging からログベース指標を作成 ● Alerting Policy で Slack へ通知
  52. 52. Wrap Up
  53. 53. Wrap Up ● CETの取り組み ● API ○ GKE, Kubernetes, Bigtable ● リアルタイム処理 ○ Pub/Sub, Dataflow
  54. 54. Thank You.

×