【问题标题】:A single erlang process eating up more memory and firing process memory high alarms单个 erlang 进程占用更多内存并触发进程内存高警报
【发布时间】:2016-07-19 17:43:12
【问题描述】:

我有一个 erlang gen_server,它异步接收来自客户端的消息(使用强制转换)。在每次消息处理时,服务器将它们插入到有序的 ETS 表中,并根据条件删除其中的一些(由于条件删除,ETS 表中的记录数大部分时间在 5000 左右。但很少有可以将此大小增加到 200k 的场景,从而引入了插入和删除的开销)。

这可以正常工作,直到每秒消息数为 100k,但高于此它会给我进程内存高水位标记并开始消耗大量内存。当我注释掉有序ets的插入和删除部分时,它每秒可以处理超过100k。你能给我一些关于如何解决这个问题的提示吗?

进程可以分配的内存有最大限制吗?我正在使用 35 GB 的内存,并将水印阈值设置为 memsup:set_procmem_high_watermark(0.6)。我还尝试了 gbtree 和有序字典,但它们没有解决内存错误。

【问题讨论】:

  • 我觉得消息队列太长,你的gen_server不能快速处理消息。你能分享你的代码吗?

标签: memory-management erlang gen-server


【解决方案1】:

进程内存限制

Erlang 中没有这样的选项。 memsup:set_procmem_high_watermark/1 只是设置进程内存分配的阈值。如果超过阈值,则会发出警报。

问题的原因可能是什么?

在开始时,您必须找出进程变慢的原因。如前所述,检查消息队列的特征:它是否随着时间增长?如果是这种情况,您的进程将无法以消息到达的速度处理消息。 erlang:process_info/2 会很有帮助。

要记住的另一件事是,当您在 ETS 中插入/查找数据时,对象会被复制。因此,如果删除对象时必须满足的条件涉及从您的 ETS 中检索数据,这也可能是您的问题的原因。

如何解决这个问题?

有几种方法可以解决这个问题。显而易见的一种是简单地使用背压机制,例如让客户端同步发送消息。

或者,您可以尝试将您的一个进程正在执行的操作拆分为多个进程。为了实现这一点,您可以让一个进程根据消息中包含的某些信息将消息分发给其他进程。

最后,您可以尝试对您的 ETS 进行一些优化。例如,如果您要存储大对象,您可以检查是否没有不必要地取回它们(通过使用 ets:lookup/X 而不是 ets:match/Xets:match_object/X 从存储的消息中准确获取所需的位) .

【讨论】:

  • 我认为 ets:insert 和 delete 需要一些时间,这会导致消息队列逐渐增长(我不从 ets 读取,并且因为我使用有序 ets 进行删除,所以我删除了匹配的对象从根开始直到满足条件)。监视了一个沉重的消息队列和一个大堆。我将尝试将插入和删除分成 2 个进程。非常感谢您的建议。
  • 这里是 gen_server 的代码,包括插入和删除。如果我做的事情效率低下,请告诉我 [github.com/chathurilanchana/riak_kv/blob/…]。
【解决方案2】:

我有一个建议。当超过 100k/s 时,gen_server 无法及时处理消息队列,所以它开始增长 => gen_server 变慢并且内存泄漏。尝试监控 erlang:process_info(Pid, message_queue_len) 是否增长。

【讨论】:

  • Erlang 没有内存泄漏,但这也是我的怀疑,消息队列增长吃掉你的进程内存。 process_info 还可用于获取更多进程信息,不仅是队列长度,即分配的堆/堆栈。另一种可能性是安装recon 以更好地监控节点,另请参阅此答案:stackoverflow.com/questions/36184551/…
猜你喜欢
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 2013-01-03
  • 1970-01-01
相关资源
最近更新 更多