技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 源码分析 --> ERLANG OTP源码分析 – sys

ERLANG OTP源码分析 – sys

浏览:1308次  出处信息

    sys模块主要有两大用途.统计跟踪目标gen进程,代码热升级,尤其后者非常重要,下面从erlang源码层面来讲述这两大工作原理.

代码热升级

    代码热升级能做到gen进程不停(自然其中的socket,file都不需要关闭咯,100%的在线率多有趣的功能阿)的情况下自动载入新的代码, 这点对于其它程序语言来说是件非常难的事情,而对于erlang确只是简单几行代码就能解决问题.

演示代码

    这里有演示代码,你可以自行运行.

热升级的原理和步骤

    1.首先gen进程已经启动并处于正常工作状态处理业务逻辑,现在需要对代码进行升级,修改原来的内部State状态.

    2.修改代码,编译出新的beam文件.

compile:file(Mod).

    注意不能使用c(Mod). c命令实际包含一个编译和加载和清理老代码作用,这里还不能加载哦, 老的内存状态运行在新的代码肯定报错.

    3.利用sys:suspend函数使得gen进程陷入一种挂起状态.

     这种挂起状态的gen进程仅仅会处理system和’EXIT’两类的消息,而不会处理业务逻辑.

sys.erl
====
suspend_loop(SysState, Parent, Mod, Debug, Misc, Hib) ->
    case Hib of
    true ->
       suspend_loop_hib(SysState, Parent, Mod, Debug, Misc, Hib);
    _ ->
        receive
        {system, From, Msg} ->
            handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib);
        {\\\'EXIT\\\', Parent, Reason} ->
            Mod:system_terminate(Reason, Parent, Debug, Misc)
        end
    end.

    此时发送过来的业务消息都被存在mailbox中,而代码不会走到业务模块.

    4.因为业务不会运行了,所以清理老代码,载入新代码,

code:purge(Mod).
code:load_file(Mod).

    好了这个时候已经新的代码了.而gen进程里的内存状态还是老状态(State).

    5. 调用change_code做一个内存状态的转化.

sys:change_code(Name, Mod, OldVsn, Extra).

    change_code属于system消息,告诉gen进程去调用Mod里的code_change函数,针对的vsn是OldVsn,额外的参数是Extra.于是gen进程最终就调用Mod里的code_change函数,内存State在此时进行了转化.

    6.回到业务逻辑

sys:resume(swap_test).

    好了代码,内存里的信息都是正确的了,我们就开启业务,resume最终会让gen进程跑到system_continue这个函数

system_continue(Parent, Debug, [Name, StateName, StateData, Mod, Time]) ->
    loop(Parent, Name, StateName, StateData, Mod, Time, Debug).

    于是gen进程又走回到正常的业务逻辑loop函数去,于是积累的消息和新的消息就开始正常的处理了.

    \"\"

    release_handler_1.erl底层也是调用sys模块进行代码热升级的,所以立即sys的工作原理很重要.

统计跟踪

    开启统计

sys:statistics(Name, true).

    实际上是开始记录了一个初始值

init_stat() -> {erlang:localtime(), process_info(self(), reductions), 0, 0}.

    现在使用sys:statistics(Name,get)就可以获得进程的运行时间和处理过的消息数目了.

3> sys:statistics(swap_test, get).
{ok,[{start_time,{{2012,7,31},{19,58,25}}},
     {current_time,{{2012,7,31},{19,58,32}}},
     {reductions,18},
     {messages_in,0},
     {messages_out,0}]}

    关闭统计

sys:statistics(Name, false).

    获取进程和进程内字典的信息

5> sys:get_status(swap_test).
{status,,
        {module,gen_server},
        [[{\\\'$ancestors\\\',[]},
          {\\\'$initial_call\\\',{swap_test,init,1}}],
         running,,[],
         [{header,\"Status for generic server swap_test\"},
          {data,[{\"Status\",running},
                 {\"Parent\",},
                 {\"Logged events\",[]}]},
          {data,[{\"State\",{state,1,2}}]}]]}

    最终调用的是sys.get_status和gen进程里的format_status/2函数

get_status(SysState, Parent, Mod, Debug, Misc) ->
{status, self(), {module, Mod},
[get(), SysState, Parent, Debug, Misc]}.

    跟踪进程

sys:trace(code_lock, true).

    实际上使得gen进程在处理每一条消息的时候多调用一次print_event函数打印出这条信息和前后状态.

Debug1 = sys:handle_debug(Debug, {?MODULE, print_event},
Name, {in, Msg}),

    看看激活trace后的效果

4> swap_test:test_call().
*DBG* swap_test got call counter from 
call counter 
*DBG* swap_test sent 1 to , new state {state,3,2}

    以上就是sys模块的重要功能.

建议继续学习:

  1. Nginx源码分析-事件循环    (阅读:4705)
  2. Hive的入口 -- Hive源码解析    (阅读:4673)
  3. Storm源码浅析之topology的提交    (阅读:4202)
  4. Hive源码解析-之-语法解析器    (阅读:4114)
  5. Nginx源码分析-内存池    (阅读:4038)
  6. Nginx源码分析-Epoll模块    (阅读:3811)
  7. Lua GC 的源码剖析 (2)    (阅读:3767)
  8. Lua GC 的源码剖析 (4)    (阅读:3288)
  9. Redis的事件循环与定时器模型    (阅读:3022)
  10. ExtJS源码研究笔记之总评    (阅读:2960)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1