protoactor-goで Pregelを作った話

protoactor-goで Pregelを作った話

protoactor-goを用いて大規模グラフプロセッシングフレームワークのPregelを実装した話

9a4b51c26825fa04a2b2228e7380029d?s=128

rerorero

July 17, 2019
Tweet

Transcript

  1. protoactor-goで Pregelを作った話 rerorero mercari.go #9 2019/7/17

  2. グラフプロセッシング

  3. 大規模グラフの計算 - 高級なマシンを使うか、MapReduceが主流 - MapReduceはステートレス。グラフプロセッシングでは計算のステップごとの結果 を次のステップに渡す必要があり、これが膨大になるためI/Oが多く発生し効率が 悪い

  4. Pregel - Googleが内製した、大規模な有向グラフに対してアルゴリズムを実行するための スケーラブルなフレームワーク - 2010年に同名の論文を発表 - コモディティハードウェアで大規模グラフの計算が効率的に行えるようになった

  5. Pregelの仕組み - グラフのノード間でメッセージを送信しあう - ノードはアクティブ・非アクティブの状態を持つ - メッセージを受け取らないなど、特定の条件でノードは非アクティブになる - すべてのノードが非アクティブになったら計算終了 -

    特定の計算アルゴリズムに依存しない - Pregelに向かないアルゴリズムもある
  6. 3 6 1 2 例: 最大値 値 アクティブノード 値 非アクティブノード

    値 値が更新されたノード メッセージ
  7. 3 6 1 2 例: 最大値 3 6 6 2

    2 1 値 アクティブノード 値 非アクティブノード 値 値が更新されたノード メッセージ
  8. 6 6 6 2 例: 最大値 3 6 6 2

    2 1 値 アクティブノード 値 非アクティブノード 値 値が更新されたノード メッセージ
  9. 6 6 6 2 例: 最大値 3 6 6 2

    2 1 値 アクティブノード 値 非アクティブノード 値 値が更新されたノード メッセージ 自分より大きい値 を受け取ったらそ の値で更新 値を更新しなかっ たら非アクティブ
  10. 6 6 6 2 例: 最大値 値 アクティブノード 値 非アクティブノード

    値 値が更新されたノード メッセージ
  11. 6 6 6 2 例: 最大値 6 6 値 アクティブノード

    値 非アクティブノード 値 値が更新されたノード メッセージ
  12. 6 6 6 6 例: 最大値 6 6 値 アクティブノード

    値 非アクティブノード 値 値が更新されたノード メッセージ
  13. 6 6 6 6 例: 最大値 値 アクティブノード 値 非アクティブノード

    値 値が更新されたノード メッセージ
  14. 6 6 6 6 例: 最大値 6 値 アクティブノード 値

    非アクティブノード 値 値が更新されたノード メッセージ
  15. 6 6 6 6 例: 最大値 6 値 アクティブノード 値

    非アクティブノード 値 値が更新されたノード メッセージ
  16. Pregelの仕組み - 1つのマスターと複数のワーカーでクラスタを構成する - 複数ノードをパーティションと言う単位でまとめて扱う - パーティションの分割ルールに決まりはない - パーティションは任意の1つのワーカーに配置される

  17. Pregel構成例 ノード ノード ノード ノード ノード パーティション パーティション ワーカー ノード

    ノード パーティション ワーカー マスター Graph Database
  18. どうやって作る? - 分散システム - ノードの計算結果をメモリに持つ&局所性が必要 - ワーカー、パーティション、ノードという複数のステートマシンが存在し、木構造を構 成して通信しあう

  19. アクターモデル

  20. アクターモデル - 並行計算モデル - 競合を回避したい - メッセージパッシング

  21. アクターモデル

  22. アクターモデル Goにはchannelがあるのにこ れ必要?

  23. アクターモデル vs channel アクターモデル (protoactor-go) channel (CSP) 宛先を明示的に指定する 宛先を指定しない 送信時ブロッキングしない

    (メッセージボックスがあふれる可能性) ブロッキングする (デッドロックする可能性) アクターツリー(親子関係)を構築できる ツリー構築は提供していない goroutineの同期ポイント リモートプロセスとも通信できる シングルプロセス内で利用 耐障害性 親アクターが子アクターのリカバリーをする 自動復旧はしない ライブラリによって提供 Go言語によって提供
  24. アクターモデルを使いたいケース - リモート = 分散システム - ステートフル = 状態の競合を避けたい、局所化したい -

    耐障害性
  25. アクターモデルが使えそうなケース - チャットサーバーやゲームサーバー - ユーザーアクティビティを一箇所で管理する - TIS社ではペイメントサービスで利用 - イベントソーシングと組み合わせ、ユーザーの残高更新を一箇所で行うことで 整合性を保つ

    - 「Using Akka Cluster for a payment service」 - https://speakerdeck.com/negokaz/using-akka-cluster-for-a-payment-service?slide=33
  26. protoactor-go - アクターモデルを実装したGoのライブラリ - https://github.com/AsynkronIT/protoactor-go - Asynktronという会社がホストしている - プロダクションでも使っているらしい

  27. Hello world (アクター側) import "github.com/AsynkronIT/protoactor-go/actor" type Hello struct{ Who string

    } type HelloActor struct{} func (state *HelloActor) Receive(actorContext actor.Context) { switch msg := actorContext.Message().(type) { case Hello: fmt.Printf("Hello %v\n", msg.Who) } }
  28. Hello world (メッセージ送信) import "github.com/AsynkronIT/protoactor-go/actor" func main() { props :=

    actor.PropsFromProducer(func() actor.Actor { return &HelloActor{} }) pid, err := actor.EmptyRootContext.Spawn(props) if err != nil { // エラー処理 } actor.EmptyRootContext.Send(pid, Hello{Who: "Roger"}) }
  29. 耐障害性 - Let it crash - ハンドリングできないエラーが起きたらとにかくクラッシュ - 親のアクターが子のクラッシュを検知してリカバリーを試みる -

    クラッシュさせるには panicを使う - Supervisor Strategy - 子アクターがクラッシュした時にどうリカバリーするかをカスタマイズできる
  30. Supervisor Strategy decider := func(reason interface{}) actor.Directive { // リカバリーの方法にリスタートを選択

    return actor.RestartDirective } // 1000msec間隔で最大10回までリカバリーを試みる supervisor := actor.NewOneForOneStrategy(10, 1000, decider) props := actor. FromProducer(func() actor.Actor { return &HelloActor{} }). WithSupervisor(supervisor) pid, err := actor.EmptyRootContext.Spawn(props) if err != nil { // エラー処理 }
  31. Supervisor Strategy - One-For-One Strategy - クラッシュしたアクターのみリカバリーを試みる - All-For-One Strategy

    - すべての兄弟アクターに対しリカバリーを試みる - Exponential Backoff Strategy - One-For-Oneのリトライ間隔がExponentialに増える
  32. protoactor-go その他の機能 - .NETでも使える - リモートはgRPCで通信していて .NET ↔ Go でもクラスタを構築可能

    - 他にもPython, Kotlin, JavaScriptのリポジトリも存在(動くかは不明・・) - plugin - メッセージをフックする処理を定義し、差し込むことができる - router - メッセージの送信先を複数アクターから 1つ選択する際の選択条件を指定できる - Virtual Actor - アクターモデルをさらに抽象化して Location TransparencyやAutomatic Scaleなどを提供する - MicrosoftのOrelansという論文がベース - Consulクラスタも別途必要になる
  33. 作ったもの Prerogel https://github.com/rerorero/prerogel - 最大値(maximum)と単一視点最短経路(sssp)のサンプルコード - たくさんマシンを借りて動かしてみたい(まだやってない) - k8sでスケールしたい -

    ※Spark on k8s があるらしいので、まともなやつが欲しい人は試してみるとい いかもしれません - protoactor-goのおかげで1ヶ月くらいでそこそこ動くものができた
  34. 使ってみた感想 - アクターモデルは要件に合っていれば便利 - Goでアクターを使いたい場合はprotoactor-go一択(個人の見解です) - アクターモデルありきなら、成熟度という意味ではGo以外の選択肢も考えてもよさ そう(Erlang, Akka)

  35. ご清聴ありがとうございました 参考文献 - A universal modular ACTOR formalism for artificial

    intelligence: https://dl.acm.org/citation.cfm?id=1624804 - Microsoft Orleans: https://dotnet.github.io/orleans/ - Pregel A system for Large-Scale Graph Processing: https://www.cs.cmu.edu/~pavlo/courses/fall2013/static/papers/p135-malewicz.pdf - Apache Giraph: https://giraph.apache.org/ - A Bridging Model for Parallel Computation: http://web.mit.edu/6.976/www/handout/valiant2.pdf