Supervisor — 슈퍼바이저를 구현하는 behaviour 모듈
Supervisor — 슈퍼바이저를 구현하는 behaviour 모듈
Elixir/OTP에서 장애 허용(fault-tolerance) 의 중심에 서는 것이 바로 슈퍼바이저(Supervisor)예요. Supervisor는 슈퍼바이저를 구현하기 위한 behaviour 모듈이에요.
출처: Supervisor — A behaviour module for implementing supervisors
본문
슈퍼바이저는 다른 프로세스들을 감독하는 프로세스예요. 이때 감독받는 프로세스를 자식 프로세스(child processes) 라고 불러요. 슈퍼바이저들은 계층적인 프로세스 구조, 즉 감독 트리(supervision tree) 를 만드는 데 사용돼요. 감독 트리는 장애 허용성을 제공하고, 애플리케이션이 어떻게 시작되고 종료되는지를 캡슐화해요.
슈퍼바이저는 두 가지 방식으로 시작할 수 있어요.
start_link/2를 통해 자식 스펙(child specifications)의 리스트를 직접 넘겨서 시작- 필요한 콜백을 구현하는 모듈 기반(moduled-based) 슈퍼바이저를 정의해서 시작
대부분의 예제는 start_link/2로 슈퍼바이저를 시작하지만, 문서에는 모듈 기반 슈퍼바이저에 대한 별도 섹션도 있어요.
예제
슈퍼바이저를 시작하려면 먼저 감독할 자식 프로세스를 정의해야 해요. 예로 카운터를 유지하는 제네릭 서버인 GenServer를 정의해 볼게요. 다른 프로세스들은 이 프로세스에 메시지를 보내 카운터를 읽거나 값을 올릴 수 있어요.
defmodule Counter do
use GenServer
def start_link(arg) do
GenServer.start_link(__MODULE__, arg)
end
end
면책 조항(Disclaimer): 실제로 카운터를 GenServer로 정의할 일은 없어요. 카운터가 필요하면 그것을 함수의 입력·출력으로 그냥 넘겨 다니면 되거든요. 이 예제에서 카운터를 고른 이유는 단순해서 슈퍼바이저가 어떻게 동작하는지에 집중할 수 있기 때문이에요.
감독 트리와 장애 처리
감독 트리는 위에서 아래로 구성돼요. 최상위에 최상위 슈퍼바이저가 있고, 그 아래에 자식으로 워커(worker)나 또 다른 슈퍼바이저가 붙어요. 자식이 비정상적으로 종료되면 슈퍼바이저는 설정된 재시작 전략(strategy) 에 따라 해당 자식을 다시 시작해요. 이렇게 하면 단일 프로세스가 죽더라도 시스템 전체가 죽지 않고 회복될 수 있어요.
슈퍼바이저가 자식을 다시 시작하는 방식은 :one_for_one, :one_for_all, :rest_for_one, :simple_one_for_one 같은 strategy로 정해요. 어떤 자식이 죽었을 때 그 자식만 다시 시작할지, 형제들까지 전부 재시작할지가 전략에 따라 달라져요.
더 알아보기
- 시작:
Supervisor.start_link/2,Supervisor.start_link/3 - 콜백:
Supervisor.init/1(모듈 기반 슈퍼바이저) - 관리:
Supervisor.terminate_child/2,Supervisor.restart_child/2,Supervisor.count_children/1,Supervisor.which_children/1 - 관련 모듈:
Supervisor.Spec(자식 스펙, 단 deprecated),DynamicSupervisor,Application - 가이드:
supervisor-and-application(Registries and supervision trees)