Почему дерево супервизии вместо одного централизованного супервизора?
Я изучаю Elixir и Erlang/OTP и хотел бы понять важность наличия дерева надзора при создании высокодоступной системы.
Я понимаю важность супервизора в управлении временем жизни рабочих процессов. Но я все же хотел бы знать, почему некоторым приложениям необходимо организовывать супервизоров в виде иерархий, вместо того, чтобы иметь одного супервизора для управления всеми работниками? Есть ли какие-то практические преимущества в наличии таких структур, которые я наивно упустил из виду?
Заимствуя пример из книги Programming Elixir, в каком сценарии мы предпочитаем первую структуру второй структуре?
1. MainSupervisor
├── StashWorker
└── SubSupervisor
└──SequenceWorker
2. MainSupervisor
├── StashWorker
└── SequenceWorker
1 ответ
Вы, вероятно, упускаете из виду знаменитую философию "дайте сбой", которая вызывает сбой процессов и перезапускает первоклассный гражданин в OTP. Мы не рассматриваем сбои процесса как сбои, а скорее как возможность повторить их должным образом без необходимости вручную обрабатывать ошибки.
Основная причина заключается в том, чтобы позволить более детальный контроль над тем, что должно было быть перезапущено в случае сбоя. Для этого у нас есть strategies
. Или, как повторил @Andree в комментариях:
Организуя надзор в иерархии, мы обеспечиваем более детальный контроль над тем, как система должна реагировать в случае отказа части системы.
Представьте себе приложение, в котором есть процесс, отвечающий за удаленное соединение, и набор процессов, использующих этот ресурс. Когда процесс подключения завершается сбоем, он в любом случае перезапускается его супервизором, но егоpid
изменения. Имея в виду весь процесс, основанный на этомpid
также должен был быть перезапущен. С:rest_for_one
Стратегия очень проста "из коробки".
Другой подход к этому конкретному примеру - управлять соединением в процессе, контролируемым в другой части дерева, и при проблемах с соединением вручную вывести из строя супервизор пулов, использующий это соединение для повторной инициализации всех из них.
Более того, мы могли бы захотеть вручную остановить процесс, обрабатывающий это соединение, чтобы повторно инициализировать его, вместо того, чтобы писать защитный код вроде if no_conn, do: reload_config_and_restart_connection
мы просто даем ему сбой и снова инициализируемся деревом надзора с новой правильной конфигурацией.
И последнее, но не менее важное: если супервизор не ловит выходы, он также выйдет из строя, распространяя его вверх. Таким образом, мы могли бы повторно инициализировать всю ветвь дерева надзора без написания строчки кода.