主页

索引

模块索引

搜索页面

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
%

主页

索引

模块索引

搜索页面