Erlang/OTP 监督者(Supervisor)的作用是负责其子进程的启动,停止和监视。监督者的基本思路是,保持其子进程能正常运行,并在必要时重新启动子进程。
一、Erlang/OTP Supervisor 基本参数
Erlang/OTP Supervisor的基本参数有进程策略,进程id,进程启动函数,进程重启,进程关闭,进程类型,进程模块。
-module(test_sup).
-behaviour(supervisor).
-export([start_link/1, init/1]).
start_link(_) ->
io:format("test sup start link~n"),
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
{ok,
{{one_for_one, 1, 60}, % Strategy = {How, Max, Within}
[{ test_handler_worker, % Id = internal id
{test_server, start, []}, % StartFun = {M, F, A}
permanent, % Restart = permanent | transient | temporary
2000, % Shutdown = brutal_kill | int() >= 0 | infinity
worker, % Type = worker | supervisor
[test_server] % Modules = [Module] | dynamic
}]
}
}.
1、进程策略
Strategy = {How, Max, Within}
意思是在多长时间内(Within)最多允许重启了几次(Max),如何重启(HOW)。Within 和 Max 的设定意义在于限制最大重启频率,这是为了避免反复重启进入死循环。Within 以秒为单位。Max为0表示不重启。
one_for_one |
如果子进程终止,只有这个进程会被重启 |
one_for_all |
如果子进程终止,所有子进程都会被重启 |
rest_for_one |
如果子进程终止,在这个进程重启后,其他所有子进程会被重启 |
simple_one_for_one |
简化one_for_one,所有子进程都动态添加同一种进程的实例 |
one_for_one 和 simple_one_for_one 最大的区别在于:
one_for_one 用一个列表储存了所有要启动的子进程,并按顺序启动。而simple_one_for_one 用一个进程字典定义所有子进程。所以当一个监督者拥有很多子进程时,遇到进程崩溃,simple_one_for_one 效率会快很多。
2、进程id
Id = internal id
用于监督者区分子进程,必须保证唯一
3、进程启动函数
StartFun = {M, F, A}
用于监督者启动子进程的函数。M代表模块,F代表函数,A代表参数
4、进程重启
Restart = permanent | transient | tempora
表示进程遇到错误之后是否重启
permanent |
遇到任何错误导致进程终止就重启 |
temporary |
进程永远都不重启 |
transient |
只有进程异常终止的时候会被重启 |
5、进程关闭
Shutdown = brutal_kill | int() >= 0 | infinity
表示采用什么手段来关闭进程
brutal_kill |
立刻强制关闭进程 |
int() >= 0 |
等待多少毫秒后强制关闭进程 |
infinity |
当子进程也是监督者时使用,意思是给足够时间让子进程重启 |
6、进程类型
Type = worker | supervisor
告诉监督者子进程是哪种类型的进程,工作进程,还是监督进程?
7、进程模块
Modules = [Module] | dynamic
表示进程运行依赖哪些模块,仅在代码热更新时使用。使用dynamic的情况是当使用了 Erlang/OTP 发布(Release)等功能,使得Erlang/OTP 可以判断在热更新时需要哪些模块
二、Erlang/OTP Supervisor 工作流程
下面以
Erlang/OTP Application的例子为基础,继续讨论Supervisor 的工作流程。所以这个 Application 就包含了5个结构:应用模块、监督者模块、资源文件、服务端模块、处理模块。
监督者模块(test_sup.erl):
-module(test_sup).
-behaviour(supervisor).
-export([start_link/1,init/1]).
start_link(_) ->
io:format("test sup start link~n"),
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
io:format("test sup init~n"),
{ok,{
{one_for_all, 1, 60},
[{ test_handler_worker,
{ test_server, start, [test_handler] },
permanent,
2000,
worker,
[test_server,test_handler]
}]}
}.
服务端模块(test_server.erl):
-module(test_server).
-behaviour(gen_server).
-export([start/1, init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
start(Module) ->
io:format("test server start ~p~n", [Module]),
gen_server:start_link({local, Module}, ?MODULE, [], []).
init([]) ->
io:format("test server init~n"),
{ok, []}.
handle_call({test_handler, test, Name}, _From, State) ->
io:format("test server test ~p~n", [Name]),
{reply, ok, State};
handle_call(_Request, _From, State) ->
io:format("test server call nothing~n"),
Reply = ok,
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
处理模块(test_handler.erl):
-module(test_handler).
-export([test/1, stop/0]).
-define(Server, ?MODULE).
test(Name) ->
io:format("test handler test~n"),
gen_server:call(?Server, {?MODULE, test, Name}).
stop() ->
io:format("test handler stop~n"),
exit(whereis(?Server), kill),
io:format("test handler is killed~n").
资源文件(test.app) :
{application,test,
[{description,"Test application"},
{vsn,"1.0.0"},
{modules,[test_app,test_handler,test_server,test_sup]},
{registered,[test_app]},
{mod,{test_app,[]}},
{env,[]},
{applications,[kernel,stdlib]}]}.
erl编译这个Application后,执行命令启动:
1> application:start(test).
test app start
test sup start link
test sup init
test server start test_handler
test server init
ok
%% 调用处理模块函数:
2> test_handler:test(helloworld).
test handler test
test server test helloworld
ok
3> test_handler:stop().
test handler stop
test handler is killed
test server start test_handler
ok
test server init
%% 如果在60秒内重复执行以下命令,进程将被彻底关闭:
4> test_handler:stop().
test handler stop
test handler is killed
ok
=INFO REPORT==== 14-Oct-2013::19:25:49 ===
application: test
exited: shutdown
type: temporary
由此可见,到了监督者模块(test_sup),监督者模块启动了一个监督者进程,作为监督树的一部分。监督者进程会回调监督者模块的 init/1 函数,根据这个函数的返回值来启动子进程。
init([]) ->
io:format("test sup init~n"),
{ok,{
{one_for_all, 1, 60},
[{ test_handler_worker,
{ test_server, start, [test_handler] },
permanent,
2000,
worker,
[test_server,test_handler]
}]}
}.
以上参数告诉监督者调用 test_server:start(test_handler) 来启动工作进程,采用 one_for_all 的重启策略,如果60秒内重启超过1次就不再重启子进程,否则就会守护进程的正常运行。
文章完整例子下载
http://download.csdn.net/detail/cwqcwk1/6398337
分享到:
相关推荐
1. 监督树(Supervision Trees):监督树是Erlang/OTP的核心概念之一,它是一种分层的组织结构,用于管理进程的生命周期。在这个结构中,有两类主要的进程类型:工作者进程(Worker Processes)和监督进程...
监督树是基于监督者(supervisor)和工作进程(worker)的结构化模型,旨在提供一种层次化的、可以处理故障并恢复的系统架构。监督者负责监控和管理工作进程,当检测到工作进程失败时,监督者可以根据预定的策略来...
- **OTP行为**:如Supervisor(监督者)、GenServer(通用服务器)、GenEvent(事件处理器)等,它们是构建可靠系统的基石。 - **Erlang shell(REPL)**:交互式环境,用于测试和调试代码。 - **Erlang的数据类型...
简单来说,监督树中的每一个节点都代表着一个进程,它要么是一个监督者,负责管理其他进程的生命周期,要么是一个执行具体任务的工作者。 行为(Behavior)模式是Erlang OTP设计中的一种代码复用机制。在很多情况下...
每个节点都是一个监督者(Supervisor),它可以监控并管理一组子进程,这些子进程可以是其他监督者或工作进程(Workers)。当子进程出错时,监督者可以决定如何恢复,如重启进程、重新初始化或完全停止应用。这种...
OTP的核心理念之一是“supervisor”(监督者),这是一种错误处理机制,能够在系统出现故障时自动恢复服务,确保系统的稳定性。 Homelander充分利用了Erlang OTP的特性,通过建立一个监督树来管理和监控shell命令的...
标题中的“导演”(Director)实际上是在Erlang和Elixir编程语言中提到的一个概念,它与OTP(Open Telephony Platform)框架中的监督者(Supervisor)行为有关。OTP是Erlang的一项核心特性,旨在提供可靠、容错的...
在Erlang的 OTP(Open Telecom Platform)框架中,监督者是一种特殊类型的进程,用于管理和监控其他进程,确保系统的容错性。当被监督的进程崩溃时,监督者可以按照预定义的策略重启它或者整个子树。 5. 示例:...
Erlang是一种面向并发的、函数式编程语言,特别适合于构建高可用性和容错性的分布式系统。...这个练习帮助初学者理解Erlang OTP的设计原则和实际应用,是深入学习Erlang并发编程和系统架构的重要步骤。
在监控树中,每个节点都是一个监督者(supervisor),它可以启动并监控多个子进程。如果某个子进程崩溃,监督者可以根据预设的重启策略来决定是否重启该进程或者采取其他行动。 #### 行为(Behaviours) OTP行为是...
5. **应用框架**:OTP包含了一系列的应用框架,如Supervisor(监督者树)、GenServer(通用服务器)、GenEvent(事件管理器)等,帮助开发者构建健壮的分布式系统。 **RabbitMQ与OTP的关系:** 1. **依赖关系**:...
OTP是Erlang生态系统的核心,提供了一系列库和设计模式,如行为(Supervisor、GenServer等)、应用程序框架和工具,帮助开发者构建可靠、可维护的系统。 8. **Erlang源码分析** 配套的源码文件可以帮助读者更好地...
监督者(supervisor)是Erlang中的一个特殊进程,它的职责是监控其他进程的运行状态,并在子进程发生故障时重新启动它们。监督者通常被组织成树状结构,形成一个由父监督者管理子监督者和工作进程的层次。这种机制...
每个服务或功能通常由一个监督树管理,当子进程失败时,监督者可以重启它们或整个树。 - 在RabbitMQ中,`supervisor`进程用于管理和监控其他进程,确保在出现问题时能够恢复服务。 6. **网络和套接字操作**: - `...
1. **Erlang OTP**:理解Erlang OTP的设计原则和模式,如Supervisor(监督者)、GenServer(通用服务器)等,这对于使用eopcua库构建可靠系统至关重要。 2. **OPC UA**:学习OPC UA的架构、安全模型、数据类型和...
5. **OTP(Open Telecom Platform)框架**:OTP提供了标准库、设计原则和行为模块,如GenServer、GenEvent和Supervisor,它们为构建可靠和可维护的Erlang应用提供了坚实的基础。 6. **Eshell**:Erlang的交互式...
GenServer用于处理状态管理,GenEvent用于事件处理,而Supervisor则负责进程监督和故障恢复。 JavaScript作为另一个标签,可能意味着“facturacion”系统与前端用户界面交互的部分采用了JavaScript。JavaScript作为...