erlang 故障排查工具


 系統級別perf top, dstat -tam, vtune 都能很好分析beam 瓶頸,本文主要erlang 級別排查:

1. 反編譯

   確認線上運行代碼是否正確,reltools沒掌握好,升級偶爾出現問題

decompile(Mod) ->
    {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(code:which(Mod), [abstract_code]),
    io:format("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).

 

2. 進程棧

    類似於jstack,發現大量進程掛起,進程數過高,運行慢,hang住等問題用到

pstack(Reg) when is_atom(Reg) ->
    case whereis(Reg) of
        undefined -> undefined;
        Pid -> pstack(Pid)
    end;
pstack(Pid) ->
    io:format("~s~n", [element(2, process_info(Pid, backtrace))]).

 

3. etop

  分析內存、cpu占用進程,即使數十w進程node 也能正常使用

%進程CPU占用排名
etop() ->
    spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, reductions}]) end).

%進程Mem占用排名
etop_mem() ->
    spawn(fun() -> etop:start([{output, text}, {interval, 10}, {lines, 20}, {sort, memory}]) end).

%停止etop
etop_stop() ->
    etop:stop().

 

4. gc all

   進程內存過高時,來一發,看看是內存泄露還是gc不過來

% 對所有process做gc
gc_all() ->
    [erlang:garbage_collect(Pid) || Pid <- processes()].

 

5.  fprof

% 對MFA 執行分析,會嚴重減緩運行,建議只對小量業務執行
% 結果:
% fprof 結果比較詳細,能夠輸出熱點調用路徑
fprof(M, F, A) ->
    fprof:start(),
    fprof:apply(M, F, A),
    fprof:profile(),
    fprof:analyse(),
    fprof:stop().

 

6. eprof

% 對整個節點內所有進程執行eprof, eprof 對線上業務有一定影響,慎用!
% 建議TimeoutSec<10s,且進程數< 1000,否則可能導致節點crash
% 結果:
% 輸出每個方法實際執行時間(不會累計方法內其他mod調用執行時間)
% 只能得到mod - Fun 執行次數 執行耗時
eprof_all(TimeoutSec) ->
    eprof(processes() -- [whereis(eprof)], TimeoutSec).

eprof(Pids, TimeoutSec) ->
    eprof:start(),
    eprof:start_profiling(Pids),
    timer:sleep(TimeoutSec),
    eprof:stop_profiling(),
    eprof:analyze(total),
    eprof:stop().

 

7. scheduler usage

% 統計下1s每個調度器CPU的實際利用率(因為有spin wait、調度工作, 可能usage 比top顯示低很多)
scheduler_usage() ->
    scheduler_usage(1000).

scheduler_usage(RunMs) ->
    erlang:system_flag(scheduler_wall_time, true),
    Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)),
    timer:sleep(RunMs),
    Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)),
    erlang:system_flag(scheduler_wall_time, false),
    Cores = lists:map(fun({{I, A0, T0}, {I, A1, T1}}) ->
                    {I, (A1 - A0) / (T1 - T0)} end, lists:zip(Ts0, Ts1)),
    {A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai,Ti}) ->
                    {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0, Ts1)),
    Total = A/T,
    io:format("~p~n", [[{total, Total} | Cores]]).

 

8.  進程調度

% 統計下1s內調度進程數量(含義:第一個數字執行進程數量,第二個數字遷移進程數量)
scheduler_stat() ->
    scheduler_stat(1000).

scheduler_stat(RunMs) ->
    erlang:system_flag(scheduling_statistics, enable),
    Ts0 = erlang:system_info(total_scheduling_statistics),
    timer:sleep(RunMs),
    Ts1 = erlang:system_info(total_scheduling_statistics),
    erlang:system_flag(scheduling_statistics, disable),
    lists:map(fun({{Key, In0, Out0}, {Key, In1, Out1}}) ->
                {Key, In1 - In0, Out1 - Out0} end, lists:zip(Ts0, Ts1)).

 

9. trace 日志

  會把mod 每次調用詳細MFA log 下來,args 太大就不好看了

%trace Mod 所有方法的調用
trace(Mod) ->
    dbg:tracer(),
    dbg:tpl(Mod, '_', []),
    dbg:p(all, c).

%trace Node上指定 Mod 所有方法的調用, 結果將輸出到本地shell
trace(Node, Mod) ->
    dbg:tracer(),
    dbg:n(Node),
    dbg:tpl(Mod, '_', []),
    dbg:p(all, c).

%停止trace
trace_stop() ->
    dbg:stop_clear().

 

10. 內存高OOM 排查工具

  etop 無法應對10w+ 進程節點, 下面代碼就沒問題了;找到可疑proc后通過pstack、message_queu_len 排查原因

  proc_mem_all(SizeLimitKb) ->
      Procs = [{undefined, Pid} || Pid<- erlang:processes()],
      proc_mem(Procs, SizeLimitKb).

  proc_mem(SizeLimitKb) ->
      Procs = [{Name, Pid} || {_, Name, Pid, _} <- release_handler_1:get_supervised_procs(),
                              is_process_alive(Pid)],
      proc_mem(Procs, SizeLimitKb).

  proc_mem(Procs, SizeLimitKb) ->
      SizeLimit = SizeLimitKb * 1024,
      {R, Total} = lists:foldl(fun({Name, Pid}, {Acc, TotalSize}) ->
          case erlang:process_info(Pid, total_heap_size) of
              {_, Size0} ->
                  Size = Size0*8,
                  case Size > SizeLimit of
                      true -> {[{Name, Pid, Size} | Acc], TotalSize+Size};
                      false -> {Acc, TotalSize}
                  end;
              _ -> {Acc, TotalSize}
              end
          end, {[], 0}, Procs),
      R1 = lists:keysort(3, R),
      {Total, lists:reverse(R1)}.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM