soranoba
soranoba Author of soranoba.net
programming

OTP23から入るpgのコードを読む

最近は久しぶりにプロダクションでErlangのコードを書いたりしています. かなり小規模な物ですが.
そこでOTP23で新しく入るpgのコードを読む機会があったので, pgの実装についてまとめようと思います.

pg (Process Group) とは

Erlang Cluster内で複数のプロセスが参加するグループを作成し, そのグループの全てのプロセスに対してメッセージを送信することを目的としたものです.

そもそもpgというモジュールは昔存在しており, このページ では以下のように書かれています.

This module is deprecated and will be removed in Erlang/OTP 18.

その代わりとしてpg2が現れ, そしてまたpgが帰ってきました.
といっても名称が同じなだけで全く別物であり, WhatsApp IncのMaxim Fedorovが作成したもので, spgに軽微な修正が入った物です.

pg2は誰も使っていないと揶揄される程一般的ではないようで, gproc, synといったプロセスグループを扱えるライブラリが乱立している状態でした.
私は新しいpgの実装は素晴らしいものだと思いましたが, 必ずしも全てのケースで優位である訳ではありません. その点に注意する必要があります.
なお, pg2はOTP23からdeprecatedになります.

pg2 will be deprecated in OTP 23 and scheduled for removal in OTP 24.

pgの特徴

今回入ったpgにはいくつか特徴的な点があります.

  • 自ノードのプロセス一覧は常に正しい
  • 他ノードのプロセス一覧は一時的に不整合になることは許容されるが, 整合状態に戻る
  • グローバルロックは取らない
  • プロセスの一覧の取得は高速 (プロセス間通信を行わない / ETS)
  • pgが構成するOverlay Networkの構成は定義する必要がない (adhocに変更可能)

確実にメッセージを届けられる訳ではないので, RDBのように一貫性が必要なものには適しませんが, プロセスグループが必要な多くの場合で優れているように思います. (個人の感想です)

では、実際にpgのフローを追っていきましょう.

pgのメッセージフロー

グループ参加 / 離脱時

ローカルのpgプロセスに対して同期メッセージ (call) を送信しグループに追加した後, pgプロセスは他ノードのpgプロセスに通知を行います.
ノード間の接続がされている限りメッセージの送信を行う (noconnect) ので, 同期していませんが, nodedownが発生しない限り状態がそのうち更新されることが期待されています.
また, ローカルのpgプロセスはグループに参加したプロセスをmonitorし, DOWN時に自動的にグループ離脱処理を行います.

nodeup / nodedown時

nodeupが発生した場合に, discoversyncのメッセージでpgプロセスはノード間で相互に状態の更新を行います.
リモートのpgプロセスをpgプロセスはmonitorし, DOWN時に自動的にそのノードのプロセスを全グループから削除する処理を行います.
DOWN時なので, リモートのpgプロセスが異常終了した場合も対象になります.

pgのパフォーマンス

本来であれば自分でパフォーマンスを測定したいのですが, spgのレポジトリに記載されている内容を引用します.

Join/leave calls are routed through local spg scope process. Local processes joined the group are monitored. When spg scope detects monitored process exit, leave message is sent to all nodes of an overlay network.

Handling remote spg scope ‘DOWN’ includes removal of all processes owned by remote node from the scope.

Join/leave operations contain originating scope process. This speeds up handling of node/scope down/up notifications. Tests were performed on a cluster of 5,000 machines, and up to 150,000 processes joining ~5,000 different groups within a single scope.

If you need to handle more groups and processes, it is advised to run multiple scopes. It is more efficient to have 10 scopes with 100 groups than 1 scope with 1000 groups, due to concurrent processing allowed when running multiple scope processes.

Relies on message ordering done by Erlang distribution. All exchanges are happening only between corresponding spg gen_server processes.

spg - Join/leave protocolより引用

5kノード, 合計15kプロセス, 5kプロセスグループでテストしているようです.
また, スコープを分割することでパフォーマンスを向上させることが可能ですが, その場合はどのスコープに割り振るかを一意に決定する必要があります.

おわりに

OTP23で新たに追加される pg (spg) の紹介でした.
今後利用者が増えて, パフォーマンスに関する記事が出てくることを期待したいところです.

参考文献

(Updated: )

comments powered by Disqus