我们有一个处理大型json有效负载的erlang / elixir应用程序(在18 / erts 7.3.1上)。
这是一个典型的工作流程:
侦听器从rabbitmq获取一个令牌并发送到gen_server。
gen_server将令牌放入带有未来时间(当前+ n秒)的ETS表中。 gen_server中的计划作业将从ETS中获取过期的令牌,并使用这些令牌启动几个短期过程。
这些短暂的进程从elasticsearch(使用hackney)下载30-50k json有效负载并对其进行处理,然后将结果上传回elasticsearch,然后进程立即死亡。我们跟踪这些过程并确认它们已经死亡。我们每秒处理5-10个这样的请求。
问题:我们看到一个不断增长的二进制空间,并且在48小时内它增长到几个GB(通过观察者和调试打印看到)。手动GC也没有影响。
我们已经添加了“recon”并运行了recon:bin_leak,但是这只会释放几KB并且不会对不断增长的二进制空间产生影响。
堆栈:Erlang 18 / erts 7.3.1,elixir 1.3.4,hackney 1.4.4,毒药2.2.0,timex 3.1.13等,这些应用程序都没有内存。
过去有没有人遇到过类似的问题?非常感谢任何解决方案。
2009年9月15日更新:
我们更新了我们的应用程序到Erlang 19 / ERTS 8.3和hackney和毒药库到最新,仍然没有进展。这是GenServer中的一些日志,它使用spawn / receive或send_after定期向自己发送消息。在每个handle_info中,它查找一个ets表,如果它找到任何“符合条件”的条目,它会产生新的进程。如果没有,它只返回一个{:noreply,state}。我们在函数入口处打印VMs二进制空间信息(以KB为单位),日志列在下面。这是一天中的“空闲时间”。你可以看到二进制空间的逐渐增加。再一次:recon.bin_leak(N)或:erlang.garbage_collect()对这种增长没有影响。
11:40:19.896 [warn] binary 1:3544.1328125
11:40:24.897 [warn] binary 1:3541.9609375
11:40:29.901 [warn] binary 1:3541.9765625
11:40:34.903 [warn] binary 1:3546.2109375
---一些处理---
12:00:47.307 [warn] binary 1:7517.515625
---一些处理---
12:20:38.033 [warn] binary 1:15002.1328125
在我们的旧Scala / Akka应用程序中,我们从来没有遇到这样的情况,该应用程序多年来处理的运行量增加了30倍而没有出现问题或重新启动。我写了两个应用程序。
答案 0 :(得分:1)
我们发现memory_leak来自一个私有的可重用库,该库向Graylog发送消息,并使用下面的函数压缩该数据,然后通过gen_udp发送它。
defp compress(data) do
zip = :zlib.open()
:zlib.deflateInit(zip)
output = :zlib.deflate(zip, data, :finish)
:zlib.deflateEnd(zip)
:zlib.close(zip) #<--- was missing, hence the slow memory leak.
output
end
相反,使用term_to_binary(数据,[:压缩])我可以省去一些麻烦。
感谢所有的输入和评论。非常感谢!