[Elixir in Action]Supervision Tree ~ ネストされたSupervisor ~

メモメモ。

前回では、Supervisorというprocessの説明でした。

ここからは、エラーに関する話やSupervision Treeの話。

Supervision treesは、Supervisorによって以下見たく構成されるSupervisor – processの関係性を指します。Supervisorやworkerがlinkの関係を持ち、strategyに沿ってそれぞれのprocessを監視していきます。

defmodule Sample.Supervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__, nil)
  end

  def init(_) do
    processes = [
      worker(Todo.ProcessRegistry, []),
      supervisor(Todo.Database, ["./persist/"]),
      supervisor(Todo.ServerSupervisor, []),
      worker(Todo.Cache, [])
    ]
    supervise(processes, strategy: :one_for_one)
  end
end

Supervisorには、その子processの起動として、以下を定義しています。

  @spec start_child(supervisor, Supervisor.Spec.spec | [term]) :: on_start_child
  def start_child(supervisor, child_spec_or_args) do
    call(supervisor, {:start_child, child_spec_or_args})
  end

Supervisorは、親から子とprocessを順に起動していきます。このprocessの起動は同期的に行われます。なので、上記では worker(Todo.ProcessRegistry, []) => supervisor(Todo.Database, ["./persist/"]) => … という順に前のprocess起動が終わるのを待って次のprocessが起動していきます。

これらのworkerやsupervisorは、 Sample.Supervisor のprocessが終了するとterminateされていきます。(これがsupervisorと、その子の関係ですね)

Erlang/Elixirが提供する Supervisor では、 linkmonitor をPIDによって指定したプロセスを対象として監視していたものを、抽象化して、processにひも付けたatomによって監視します。これは、PIDはprocessがcrashした後に起動するたびに変わるためですね。

前回にもメモしていましたが、processの監視には linkmonitor があります。子processがcrashしたらそれ単体を再起動する、などしたいならlink、子processがcrashしたらそれに関係する他の子processも終了する、とか実装したいならmonitorを使う必要があります。

Supervisorには、その子processのcrash時の挙動として幾つかのstrategyを定義し、提供しています。それらから必要なstrategyを設定して、実際には運用していくことになります。この選択はfault toleranceなシステムを構築するうえで重要な要素。

  • :one_for_one – if a child process terminates, only that process is restarted.
  • :one_for_all – if a child process terminates, all other child processes are terminated and then all child processes (including the terminated one) are restarted.
  • :rest_for_one – if a child process terminates, the “rest” of the child processes, i.e. the child processes after the terminated one in start order, are terminated. Then the terminated child process and the rest of the child processes are restarted.
  • :simple_one_for_one – similar to :one_for_one but suits better when dynamically attaching children. This strategy requires the supervisor specification to contain only one child. Many functions in this module behave slightly differently when this strategy is used.

何重にもネスとしたSupervisorを作り、Tree構造を作って、必要なシステムに必要なだけ、それらの独立性も含めて耐障害性を与える。そんな感じで構築していくのがこのSupervisorの考え方ですね。(ただ、一番親まで来ると結局は中央集権的な構成になっていくので、そこは運用なんかでカバーしないといけないprocessになるのですね。)


  • 意図するエラーは適切に try/catch で処理しましょう
    • それ以外はSupervisorではprocessをcrashし、strategyに沿ったprocessの再起動を行います
    • もしDBなどに状態を保持している場合、processを再起動してもその状態が起因ですぐにprocessがまたcrashすることもあります…
  • それぞれのprocessはsupervision treeに属していて、supervisorのprocessがterminateするとそれにより監視されているprocessもterminateされます
広告

[Elixir in Action]Supervision Tree ~ ネストされたSupervisor ~」への1件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中