Erlang相关Appups/热更介绍及坑点

来源:互联网 发布:apple pencil配套软件 编辑:程序博客网 时间:2024/06/08 06:45

Appup

部分命令说明

load_module
简单代码替换,针对某功能模块部分修改,仅需载入新版本即可

{load_module, Module}

update
同步代码替换,针对进程(某个gen_server/gen_fsm/gen_statem/gen_event等)的内部状态的格式发生改变,通过调用回调函数code_change转换内部状态,特殊进程调用回调函数system_code_change/4,处理方式为挂起进程,替换内部状态,切换新版,删除旧版,恢复进程

{update, Mod}{update, Mod, supervisor}{update, Mod, Change}{update, Mod, DepMods}{update, Mod, Change, DepMods}{update, Mod, Change, PrePurge, PostPurge, DepMods}{update, Mod, Timeout, Change, PrePurge, PostPurge, DepMods}{update, Mod, ModType, Timeout, Change, PrePurge, PostPurge, DepMods}  Mod = atom()  ModType = static | dynamic  Timeout = int()>0 | default | infinity  Change = soft | {advanced,Extra}    Extra = term()   (default = > soft)  PrePurge = PostPurge = soft_purge | brutal_purge (default = > brutal_purge)  DepMods = [Mod]

附:若改变督程启动规格,则需带supervisor参数
add_module/delete_module
引入/删除模块

{add_module, Module}{delete_module, Module}

应用升级文件

Application.appup(存放ebin文件夹)

{Vsn,  [{UpFromVsn, Instructions}, ...],  [{DownToVsn, Instructions}, ...]}.

发布资源文件

.rel
通过systools:make_script生成.script启动脚本文件/.boot二进制启动脚本文件/relup文件
包含发布名称/发布版本/ERTS版本/Application版本

{release, {RelName,Vsn}, {erts, EVsn},  [{Application, AppVsn} |   {Application, AppVsn, Type} |   {Application, AppVsn, IncApps} |   {Application, AppVsn, Type, IncApps}]}.

附:必须包含Kernerl和STDLIB应用

发布升级文件

relup
通过systools:make_relup/3,4生成,调用相关版本.rel/.app/.appup文件作为输入参数
包含升级/降级说明

{Vsn,  [{UpFromVsn, Descr, Instructions}, ...],  [{DownToVsn, Descr, Instructions}, ...]}.

启动脚本文件

.script

{script, {Name, Vsn}, [  {progress, loading},  {preLoaded, [Mod1, Mod2, ...]},  {path, [Dir1,"$ROOT/Dir",...]}.  {primLoad, [Mod1, Mod2, ...]},  ...  {kernel_load_completed},  {progress, loaded},  {kernelProcess, Name, {Mod, Func, Args}},  ...  {apply, {Mod, Func, Args}},  ...  {progress, started}]}.

创建发布包

systools:make_scriptsystools:make_tar

安装发布 

SASL应用进程处理解包/安装/移除

release_handler:unpack_release(ReleaseName) => {ok, Vsn}release_handler:install_release(Vsn) => {ok, FromVsn, []}release_handler:make_permanent(Vsn) => okrelease_handler:remove_release(Vsn) => ok

附:
1.uppack_release负责解包.tar.gz文件,并在release/Vsn文件夹存在.rel文件/start.boot启动脚本/sys.config系统配置文件/relup文件
2.install_release会执行code:soft_purge清理可清理模块旧版代码,make_permanent则执行code:purge(Mod)强制清理旧版代码

热更

热更实现
Erlang热更新的秘密其实都集中在code模块,code模块是Erlang Code Server暴露出来的对外接口其职责就是把已经编译好的模块加载到Erlang的运行时环境
热更方式

%% 第一种热更新方式: {Module, Binary, Filename} = code:get_object_code(Module), code:load_binary(Module, Filename, Binary). %%code:mod_to_bin -> code:do_purge -> code:try_load_module%% 第二种热更新方式: code:purge(Module), code:load_file(Module). %% code:do_purge -> code:mod_to_bin -> code:try_load_module%% 第三种热更新方式: code:soft_purge(Module) andalso code:load_file(Module). %%code:do_soft_purge -> code:mod_to_bin -> code:try_load_module

以上方式,第三种和前两种区别,若当前存在进程占用模块,是否kill进程强制更新,第三种选择不更新
代码加载方式
embedded—模块加赞需显示指定加载顺序,例根据启动脚本加载
interactive—系统启动加载部分必须模块,其他运行时动态加载
版本切换
代码版本包含current/old两个版本,若再次进行热更,将替换形成新的current/old版本,存留的跨两版的old进程将被kill,保证当前运行系统最多仅存在两个版本差异
附:
1.code:purge清理占用old版本代码/code:soft_purge清理未占用old版本代码,若当前module仅存在一个版本,则purge返回false,soft_purge返回true
2.erlang:check_process_code(Pid, Module)检测Processes是否运行某个Module的Old Version,若返回true,前两种则调用purge则直接kill
新旧版本产生原因
1.external call 完全限定调用Mod:Func,总是引用当前最新版本代码
2.local call 直接调用Func,仅存在模块内函数调用,存留旧版进程会继续加载旧版代码
附:为何存在本地调用,为何不全部采用外部调用?
1.外部调用通过指针查找,开销大,模块热更则会修改指针地址
2.外部调用函数代码加载,时间长,需提前获取到处函数表地址
切换实例

%% mochiwebreload(Module) ->    io:format("Reloading ~p ...", [Module]),    code:purge(Module),    case code:load_file(Module) of        {module, Module} ->            io:format(" ok.~n"),            case erlang:function_exported(Module, test, 0) of                true ->                    io:format(" - Calling ~p:test() ...", [Module]),                    case catch Module:test() of                        ok ->                            io:format(" ok.~n"),                            reload;                        Reason ->                            io:format(" fail: ~p.~n", [Reason]),                            reload_but_test_failed                    end;                false ->                    reload            end;        {error, Reason} ->            io:format(" fail: ~p.~n", [Reason]),            error    end.

坑点记录

1.模块当前进程是否可以清理旧版本

code:soft_purge(Module) = > true/falsetrue -> onefalse -> two

2.Appup文件,模块为update模式

down/upgrade in current vsnsys:suspend/1,2 => sys:change_code/4.5 => sys:resume/1,2%%code_change 尽可能取消#state{}匹配 防止匹配错误%%state存储数据尽保证可能全部刷新,避免state存在两个版本数据

3.无法soft升级

The core applications ERTS, Kernel, STDLIB, and SASL never allow read soft upgrade