Erlang 内存泄漏分析

乘机项目尤为依赖Erlang,碰到的问题吗随即增多。前段时间线达系统碰到内存高消耗问题,记录转troubleshooting的分析过程。线及系统就此的是Erlang
R16B02本子。

题目讲述

发生几台线上系,运行一段时间,内存飙升。系统模型很粗略,有网络连接,pool中摸索新的process进行拍卖。top命令观察,发现内存都被Erlang进程被吃罢了,netstat命令查看网络连接数,才区区几K。问题应是Erlang内存泄漏了。

分析方法

Erlang系统有个便宜,可以直接进入线上系统,在养现场分析问题。我们系是透过Rebar管制之,可以据此不同方式上线及系统。

本机登录

得一直登录到线上机器,然后经以下命令attach到Erlang系统里面

$ cd /path/to/project
$ rel/xxx/bin/xxx attach
(node@host)> 

通过remote shell

获取Erlang系统的cookie

$ ps -ef |grep beam  %%找到参数 --setcookie

新起来一个shell,使用同样的cookie,不同之nodename

$ erl --setcookie cookiename -name test@127.0.0.1

就此start remote shell进入系统

Erlang R16B02 (erts-5.10.3) [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.10.3  (abort with ^G)
(test1@127.0.0.1)1> net_adm:ping('node@127.0.0.1').
pong
(test1@127.0.0.1)2> nodes().
['node@127.0.0.1']
(test1@127.0.0.1)3> 
User switch command
 --> h
  c [nn]            - connect to job
  i [nn]            - interrupt job
  k [nn]            - kill job
  j                 - list all jobs
  s [shell]         - start local shell
  r [node [shell]]  - start remote shell
  q                 - quit erlang
  ? | h             - this message
 --> r 'node@127.0.0.1'
 --> j
   1  {shell,start,[init]}
   2* {'node@127.0.0.1',shell,start,[]}
 --> c 2

分析流程

Erlang有为数不少器,可以分析系统信息,比如appmon,webtool。但是系统内存严重不足,已经没办法启动这些家伙了,幸好还有Erlang
shell。

Erlang
shell自带了众灵光之命令,可以就此help()方法查看

> help().

Erlang系统内存消耗情况

top结果显示,是内存问题,所以首先步可先行瞧Erlang的网内存消耗情况

> erlang:memory().

memory()足见见Erlang
emulator分配的内存,有总的内存,atom消耗的内存,process消耗的内存等等。

Erlang process创建数量

丝及系统发现根本内存消耗都以process上面,接下要分析,是process内存泄漏了,还是process创建数量最为多招。

> erlang:system_info(process_limit).  %%查看系统最多能创建多少process
> erlang:system_info(process_count).  %%当前系统创建了多少process

system_info()归来时网的有消息,比如系统process,port的数。执行方命令,大吃一惊,只来2,3k的网络连接,结果Erlang
process已经生10大多w了。系统process创建了,但是因为代码或者其它由,堆积没有自由。

查单个process的信息

既然是坐process因为某种原因堆积了,只能由process里摸索原因了

预先要收获堆积process的pid

> i().  %%返回system信息
> i(0,61,886).  %% (0,61,886)是pid

看看有那么些process
hang在那里,查看具体pid信息,发现message_queue有几乎久信息并未受处理。下面就是因此到强的erlang:process_info()艺术,它好博进程相当丰富的消息。

> erlang:process_info(pid(0,61,886), current_stacktrace).
> rp(erlang:process_info(pid(0,61,886), backtrace)).

翻过程的backtrace时,发现下面的信

0x00007fbd6f18dbf8 Return addr 0x00007fbff201aa00 (gen_event:rpc/2 + 96)
y(0)     #Ref<0.0.2014.142287>
y(1)     infinity
y(2)     {sync_notify,{log,{lager_msg,[], ..........}}
y(3)     <0.61.886>
y(4)     <0.89.0>
y(5)     []

process在处理Erlang第三正值的日志库lager时,hang住了。

题材由

查阅lager的文档,发现以下信息

Prior to lager 2.0, the gen_event at the core of lager operated
purely in synchronous mode. Asynchronous mode is faster, but has no
protection against message queue overload. In lager 2.0, the
gen_event takes a hybrid approach. it polls its own mailbox size and
toggles the messaging between synchronous and asynchronous depending
on mailbox size.

{async_threshold, 20}, {async_threshold_window, 5}

This will use async messaging until the mailbox exceeds 20 messages,
at which point synchronous messaging will be used, and switch back to
asynchronous, when size reduces to 20 – 5 = 15.

If you wish to disable this behaviour, simply set it to ‘undefined’.
It defaults to a low number to prevent the mailbox growing rapidly
beyond the limit and causing problems. In general, lager should
process messages as fast as they come in, so getting 20 behind should
be relatively exceptional anyway.

原本lager有个布局起,配置message未处理的数目,如果message堆积数超出,则会就此 同步 方式处理!

目前系统打开了debug log,洪水般的log把系统为冲垮了。

鬼子也碰到类似问题,这个thread受咱们的分析带来许多Oracle辅助,感谢一下。

总结

Erlang提供了增长的工具,可以在线上系统,现场分析问题,这个特别有助于迅速、快速的定位问题。同时,强大的Erlang
OTP让系统来重复安定的管。我们尚会延续挖掘Erlang,期待有再多的履分享。

 

有关作者

微博@liaolinbo,云巴上位工程师。曾于Oracle工作。

相关文章