shijiang1130 发表于 2016-01-04 21:33

如何使用Erlang进行热更新

如何使用Erlang进行热更新?

%% 第一种热更新方式:
{Module, Binary, Filename} = code:get_object_code(Module),   
code:load_binary(Module, Filename, Binary).

%% 第二种热更新方式:
code:purge(Module), code:load_file(Module).

%% 第三种热更新方式:
code:soft_purge(Module) andalso code:load_file(Module).
前面两种从erlang内部实现上来说是一样的,区别是对外接口不同。第三种和前面两种的区别是,如果当前仍有进程占用模块时是否杀掉进程强制更新,第三种则选择不更新。


erlang如何做到热更新的?

erlang VM为每个模块保存了2份代码,当前版本 'current' 和旧版本'old'。当模块第一次被加载时,代码就是'current'版本。如果有新的代码被加载,'current'版本代码就变成了'old'版本,新的代码就成了'current'版本。erlang用两个版本共存的方法来保证任何时候总有一个版本可用,对外服务就不会停止。

如何在热更新的时候不影响进程运行?erlang VM使用code index为代码建立多个索引版本,加载新的代码过程中直到加载完之前,这个新的代码是不可用的。


为什么会有 purge 代码?

关于热更新,就要看下Code Server模块的源代码\code_server.erl

1、第一种方式:

code:get_object_code调用了code:mod_to_bin,code:load_binary依次调用了code:do_purge和code:try_load_module。

过程是:code:mod_to_bin -> code:do_purge -> code:try_load_module

2、第二种方式:

code:purge调用了code:do_purge,code:load_file依次调用了code:mod_to_bin和code:try_load_module。

过程是:code:do_purge -> code:mod_to_bin -> code:try_load_module

3、第三种方式:

code:soft_purge调用了code:do_soft_purge,code:load_file依次调用了code:mod_to_bin和code:try_load_module。

过程是:code:do_soft_purge -> code:mod_to_bin -> code:try_load_module

实际上都是这三个过程:

do_purge        清除旧的模块代码
mod_to_bin        获取模块二进制数据
try_load_module        加载模块
那么,热更新时,erlang要清除掉旧的模块数据,再把新的模块数据加载进运行时系统,所以需要purge

再来看下do_purge 和 do_soft_purge 的区别:



使用erlang:check_process_code() 先判断有没有进程在使用模块时,do_purge直接杀了使用模块的进程,而do_soft_purge则返回false

这里应该有同学好奇,为什么要杀了进程,不是说热更新不影响进程运行吗?

前面也提到了erlang VM为模块保存了2份代码,但就是因为只有2份,必须挪出空位装新的代码,就要删掉 'old' 版本的代码,然后把 'current'的代码改成 'old'版本。而删掉了 'old' 版本的代码,肯定会导致运行'old' 版本代码的进程执行出现异常。所以,这里就要杀掉运行 'old' 版本代码的进程。

而 erlang对用户暴露了 purge 的方法,实际上是把选择权交给用户,去选择是否杀进程,还是不杀,等到进程运行结束再更新。

patagonia2 发表于 2016-01-21 21:08

说起代码热更新,
当下最有名的当属Erlang
语言的热更新功能

终于不再用等到半夜没有人的时候再做更新了:mrgreen:
页: [1]
查看完整版本: 如何使用Erlang进行热更新