最近几天看了一下erlang的代码热替换,原本计划三天。现在花了快5天了,才刚刚有点对头。
开始我搜了一下,没有找到前人的例子,Erlang程序设计上面的热代码替换例子只不过是个替换思想,实际的应用替换要复杂的多。
我只好从API gen_server中Module:code_change/3开始看。找到OTP Design Principles (http://www.erlang.org/doc/design_principles/release_handling.html#instr)
。本以为就可以解决此问题了,后来发现只不过是个小小的救命草,接下来看了Release Handling,Releases,Appup Cookbook,systools,reltool等。
整个过程遇到了unpacke_release,install_release两个最耽误时间错误。
出现unpacke_release,install_release操作错误的原因是我没有发布第一个版本,(创建第一个版本:http://www.erlang.org/doc/system_principles/create_target.html)。
应用部署与热替换大体步骤:
一、发布第一个版本 (详细参考:http://www.erlang.org/doc/system_principles/create_target.html)
1>创建 发布.rel文件
{release, {"sellaprimeA", "1"}, {erts, "5.7.5"}, [{kernel, "2.13.5"}, {stdlib, "1.16.5"}, {sasl, "2.1.9"}, {sellaprimeA,"1.0"}]}.
2>创建第一个发布版本程序
target_system:create("sellaprimeA").
3>安装
target_system:install("sellaprimeA", "/usr/local/target_sellaprime").
4>启动程序
/usr/local/target_sellaprime/bin/erl -boot /usr/local/target_sellaprime/releases/1/start
留心:需要注意的是 target_system.erl 并没有在erlang lib中 ,需要自安添加编译。
二、代码热替换 (详细参考:http://www.erlang.org/doc/design_principles/release_handling.html#id2273657)
1>创建 发布.rel文件
2>创建 启动脚本 systools:make_script/1
3>创建 relup文件 systools:make_relup/3
4>创建 tar包 systools:make_tar/1
5>复制到发布目录下
6>解包 release_handler:unpack_release/1
7>安装 release_handler:install_release/1
8>持久化 release_handler:make_permanent/1
9>删除老的版本 release_handler:remove_release/1
三、未解决的问题:
1> 执行 unpacke_release、install_release函数操作时,必须在特定的shell下,就是启动一个发布程序的shell下。
如果我是在noshell下启动的话,我就无法执行热代码替换了。有没有其他方法?请老师赐教,谢谢!
如我必须在/usr/local/target_sellaprime/bin/erl -boot /usr/local/target_sellaprime/releases/1/start启动的shell。
2> 更新 new_area_server.erl模块时,state状态丢失,即ets:new(?MODULE,[])内存表被清空。
根据API中的设计原则上配置的sellaprime.appup(我没有看出哪里有错).
{"6",
[{"5",[{update, new_area_server,{advanced,Extra}}]}],
[{"5",[{update, new_area_server,supervisor}]}]
}.
-module(new_area_server). -behaviour(gen_server). -export([area/1, start_link/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). %% @type Thing()=autom() %% @doc langxianzeu area(Thing) -> gen_server:call(?MODULE, {area, Thing}). init([]) -> %% Note we must set trap_exit = true if we %% want terminate/2 to be called when the application %% is stopped process_flag(trap_exit, true), io:format("~p starting add ets table~n",[?MODULE]), {ok, ets:new(?MODULE,[])}. handle_call({area, Thing}, _From, State) -> Reply = compute_area(Thing), ets:insert(State,{Thing,Reply}), io:format("~n==[handle_call]=======tab=~p=====~n",[ets:tab2list(State)]), {reply, Reply, State}. handle_cast(_Msg, N) -> {noreply, N}. handle_info(_Info, N) -> {noreply, N}. terminate(_Reason, _N) -> io:format("~p stopping~n",[?MODULE]), ok. code_change(_OldVsn, N, _Extra) -> {ok, N}. compute_area({square, X}) -> io:format("~n===[new_area_server:compute_area-code_chanage-06~p~n====",[X*X]),X*X; compute_area({rectongle, X, Y}) -> X*Y.
3> 当 new_area_server中的(改变进程状态的存储方式)
init([]) ->
process_flag(trap_exit, true),
io:format("~p starting add ets table~n",[?MODULE]),
{ok, 0}.
替换为
init([]) ->
process_flag(trap_exit, true),
io:format("~p starting add ets table~n",[?MODULE]),
{ok,
ets:new(?MODULE,[])
时如何保存以前的状态
4> 其他模块的热替换还没有实践,继续实践!
5>
release_handler:unpack_release("ch_rel-2").
{error,{enoent,"/opt/target/releases/ch_rel-2.rel"}}
出现上面error的其中一个原因就是权限不足,需要用root权限