`
Yunba云巴
  • 浏览: 3602 次
  • 性别: Icon_minigender_2
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

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 genevent 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 genevent
takes a hybrid approach. it polls its own mailbox size and toggles the
messaging between synchronous and asynchronous depending on mailbox
size.

{asyncthreshold, 20}, {asyncthreshold_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给我们的分析带来很多帮助,感谢一下。

总结

Erlang提供了丰富的工具,可以在线进入系统,现场分析问题,这个非常有助于高效、快速的定位问题。同时,强大的Erlang OTP让系统有更稳定的保证。我们还会继续挖掘Erlang,期待有更多的实践分享。

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
分享到:
评论

相关推荐

    Erlang项目内存泄漏分析方法

    分析Erlang内存泄漏的流程一般遵循以下步骤: 1. 确认内存泄漏:使用像top这样的系统监控工具,观察Erlang进程的内存占用情况。如果内存消耗持续升高,那么很可能存在内存泄漏。 2. 进入线上系统:使用Rebar工具,...

    对Erlang R11B-5 ssl库的修正

    在 R11B-5 版本中,可能存在的问题可能影响了连接的稳定性和安全性,例如握手失败、内存泄漏或者性能问题。修复这些bug可能涉及改进错误处理机制、优化资源管理,以及确保协议的正确实现。 `ssl_prim` 模块则包含了...

    erl_nif 扩展erlang的另外一种方法

    7. **资源管理**:介绍如何在NIF中正确管理内存和其他系统资源,以防止内存泄漏和资源耗尽。 8. **例子和实践**:提供实际的代码示例,展示如何编写和使用简单的NIF,以及在实际项目中可能遇到的挑战。 9. **安全...

    ememc:检查 ets(或任何其他)操作期间的内存使用情况

    标题中的“ememc:检查 ets(或任何其他)操作期间的内存使用情况”指出,这是一款用于监控Erlang编程语言中的ETS(Erlang Term Storage...通过阅读源代码和运行示例,可以更全面地掌握Erlang内存管理和性能优化的技巧。

    服务器测试.zip

    7. **性能优化**:尽管Erlang天生适合处理并发,但仍然需要学习如何编写高效代码,避免内存泄漏,以及如何使用Erlang的性能分析工具进行调优。 通过深入学习和实践这个"服务器测试.e"文件,我们可以逐步掌握Erlang...

    大WaSP:大WaSP是一个简单的压力测试库

    通过模拟大量用户同时访问,可以发现系统在高负载下的性能瓶颈、内存泄漏以及可能的崩溃点,从而提前进行优化和调整,确保服务的稳定运行。 **Elixir与性能测试** Elixir的特性使其成为构建压力测试工具的理想选择...

    jak_rabbit.zip

    RabbitMQ是一个非常流行的消息中间件,它是用Erlang语言开发的,支持多种协议,包括AMQP(Advanced Message Queuing Protocol),广泛应用于Java和其他编程语言的项目中。本文将深入探讨RabbitMQ的核心概念,特别是...

    nodejs-training:NodeJs 培训

    - **内存管理**:理解 V8 的垃圾回收机制,避免内存泄漏。 ### 8. 社区与生态系统 - **NPM 包**:Node.js 拥有庞大的第三方库,覆盖各种功能,如数据库连接、模板引擎、测试工具等。 - **社区支持**:Stack ...

Global site tag (gtag.js) - Google Analytics