erlang 故障排查工具

    xiaoxiao2025-10-12  9

    系统级别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)}.

    本文转载自:http://www.cnblogs.com/lulu/p/4149204.html

    转载请注明原文地址: https://ju.6miu.com/read-1303096.html
    最新回复(0)