Erlang OTP¶
supervisor 树中的子进程都按照顺序、以深度优先的方式启动
{RestartStrategy, MaxR, MaxT}
在最近的MaxT秒之内有超过MaxR次数的重启,则supervisor停止它本身和它所有的子进程
one_for_one和simple_one_for_one策略适用于互相没有直接依赖关系的进程,不过
它们的集体失败还是会导致整个application的shutdown
rest_for_one:策略适用于具有线性依赖关系的进程,某子进程停止,启动顺序中在它之后的所有其他子进程也停止,然后重启这些停止进程
one_for_all 策略适用于完全相互依赖的进程
gen_server 会掌握一些资源,并且遵循 client‐server 模式(再一般化一点,就是request/response 模式)
gen_fsm 会处理事件或者输入序列,并据此作出反应,就像一个有限状态机。一般会用来实现协议
gen_event 会作为回调的事件聚合器,或者用来处理某种类型的通知
配置参数:
description:
vsn:
modules: 本应用程序引入的所有模块
registered: 本应用已注册进程的所有名称
applications: 本应用依赖的所有应用
设计原则 [1]¶
原始实现:¶
1-module(ch1).
2-export([start/0]).
3-export([alloc/0, free/1]).
4-export([init/0]).
5
6start() ->
7 spawn(ch1, init, []).
8
9alloc() ->
10 ch1 ! {self(), alloc},
11 receive
12 {ch1, Res} ->
13 Res
14 end.
15
16free(Ch) ->
17 ch1 ! {free, Ch},
18 ok.
19
20init() ->
21 register(ch1, self()),
22 Chs = channels(),
23 loop(Chs).
24
25loop(Chs) ->
26 receive
27 {From, alloc} ->
28 {Ch, Chs2} = alloc(Chs),
29 From ! {ch1, Ch},
30 loop(Chs2);
31 {free, Ch} ->
32 Chs2 = free(Ch, Chs),
33 loop(Chs2)
34 end.
35
36
37
38%%======inner method=======
39channels() ->
40 {_Allocated = [], _Free = lists:seq(1,100)}.
41
42alloc({Allocated, [H|T] = _Free}) ->
43 {H, {[H|Allocated], T}}.
44
45free(Ch, {Alloc, Free} = Channels) ->
46 case lists:member(Ch, Alloc) of
47 true ->
48 {lists:delete(Ch, Alloc), [Ch|Free]};
49 false ->
50 Channels
51 end.
OTP的plain模式实现:¶
server端:
1-module(server).
2-export([start/1]).
3-export([call/2, cast/2]).
4-export([init/1]).
5
6start(Mod) ->
7 spawn(server, init, [Mod]).
8
9call(Name, Req) ->
10 Name ! {call, self(), Req},
11 receive
12 {Name, Res} ->
13 Res
14 end.
15
16cast(Name, Req) ->
17 Name ! {cast, Req},
18 ok.
19
20init(Mod) ->
21 register(Mod, self()),
22 State = Mod:init(),
23 loop(Mod, State).
24
25loop(Mod, State) ->
26 receive
27 {call, From, Req} ->
28 {Res, State2} = Mod:handle_call(Req, State),
29 From ! {Mod, Res},
30 loop(Mod, State2);
31 {cast, Req} ->
32 State2 = Mod:handle_cast(Req, State),
33 loop(Mod, State2)
34 end.
实际实现:
1-module(ch2).
2-export([start/0]).
3-export([alloc/0, free/1]).
4-export([init/0, handle_call/2, handle_cast/2]).
5
6start() ->
7 server:start(ch2).
8
9alloc() ->
10 server:call(ch2, alloc).
11
12free(Ch) ->
13 server:cast(ch2, {free, Ch}).
14
15init() ->
16 channels().
17
18handle_call(alloc, Chs) ->
19 alloc(Chs). % => {Ch,Chs2}
20
21handle_cast({free, Ch}, Chs) ->
22 free(Ch, Chs). % => Chs2
23
24
25%%======inner method=======
26channels() ->
27 {_Allocated = [], _Free = lists:seq(1,100)}.
28
29alloc({Allocated, [H|T] = _Free}) ->
30 {H, {[H|Allocated], T}}.
31
32free(Ch, {Alloc, Free} = Channels) ->
33 case lists:member(Ch, Alloc) of
34 true ->
35 {lists:delete(Ch, Alloc), [Ch|Free]};
36 false ->
37 Channels
38 end.
OTP真正实现:¶
1-module(ch3).
2-behaviour(gen_server).
3
4-export([start_link/0]).
5-export([alloc/0, free/1]).
6-export([init/1, handle_call/3, handle_cast/2]).
7
8start_link() ->
9 gen_server:start_link({local, ch3}, ch3, [], []).
10
11alloc() ->
12 gen_server:call(ch3, alloc).
13
14free(Ch) ->
15 gen_server:cast(ch3, {free, Ch}).
16
17init(_Args) ->
18 {ok, channels()}.
19
20handle_call(alloc, _From, Chs) ->
21 {Ch, Chs2} = alloc(Chs),
22 {reply, Ch, Chs2}.
23
24handle_cast({free, Ch}, Chs) ->
25 Chs2 = free(Ch, Chs),
26 {noreply, Chs2}.
27
28
29
30%%======inner method=======
31channels() ->
32 {_Allocated = [], _Free = lists:seq(1,100)}.
33
34alloc({Allocated, [H|T] = _Free}) ->
35 {H, {[H|Allocated], T}}.
36
37free(Ch, {Alloc, Free} = Channels) ->
38 case lists:member(Ch, Alloc) of
39 true ->
40 {lists:delete(Ch, Alloc), [Ch|Free]};
41 false ->
42 Channels
43 end.
44
45
46
47
48
49
Distributed Applications¶
不同的app运行在不同的node上,当运行着app1应用的node挂掉后,会在其他node重启此app1
配置:
[{kernel,
[{distributed, [{myapp, 5000, [cp1@cave, {cp2@cave, cp3@cave}]}]},
{sync_nodes_mandatory, [cp2@cave, cp3@cave]},
{sync_nodes_timeout, 5000}
]
}
].
failover:
运行此app的node挂掉,会在其他node上启动
takeover:
运行此app的node负载重,会在其他node上启动
Releases¶
ch_rel-1.rel:
{release,
{"ch_rel", "A"},
{erts, "8.3.5.4"},
[
{kernel, "5.2.0.1"},
{stdlib, "3.3"},
{sasl, "3.0.3"},
{ch3, "0.1.0"}
]
}.
执行:
1> systools:make_script("ch_rel-1").
% 在目录下能找到ch_rel-1.rel以及ch_rel-1.rel文件下的所有App.app文件
% 生成以下2文件:
% ch_rel-1.boot % 二进制版
% ch_rel-1.script % 可读版
执行:
% erl -boot ch_rel-1
% 启动erlang并以下kernel,stdlib,sasl,ch_app
执行:
2> systools:make_tar("ch_rel-1").
% 生成ch_rel-1.tar.gz文件
Release Handling¶
Application Upgrade File:
% ch.appup
{"2",
[{"1", [{load_module, ch3}]}],
[{"1", [{load_module, ch3}]}]
}.
Release Upgrade File:
% ch_rel-2.rel
{release,
{"ch_rel", "B"},
{erts, "8.3.5.4"},
[
{kernel, "5.2.0.1"},
{stdlib, "3.3"},
{sasl, "3.0.3"},
{ch3, "0.2.0"}
]
}.
执行:
1> systools:make_relup("ch_rel-2", ["ch_rel-1"], ["ch_rel-1"]).
ok
1> systools:make_relup("ch_rel-2", ["ch_rel-1"], ["ch_rel-1"],
[{path,["../ch_rel-1", "../ch_rel-1/lib/ch_app-1/ebin"]}]).
ok
% 生成文件relup
Installing a Release:
release_handler:unpack_release(ReleaseName) => {ok, Vsn}
% ReleaseName: 是release package->ReleaseName.tar.gz文件
% Vsn: .rel文件中定义的unpacked release版本
release_handler:install_release(Vsn) => {ok, FromVsn, []}
%
release_handler:make_permanent(Vsn) => ok
%
release_handler:remove_release(Vsn) => ok
%