我们有一个处理大型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等,这些应用程序都没有内存.
过去有没有人遇到过类似的问题?将不胜感激.
2017年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]二进制1:3544.1328125
11:40:24.897 [warn]二进制1:3541.9609375
11:40:29.901 [warn]二进制1:3541.9765625
11:40:34.903 [warn]二进制1:3546.2109375
—一些处理—
12:00:47.307 [warn]二进制1:7517.515625
—一些处理—
12:20:38.033 [warn]二进制1:15002.1328125
在我们的旧Scala / Akka应用程序中,我们从来没有遇到这样的情况,该应用程序多年来处理量超过30倍而没有问题或重新启动.我写了两个应用程序.
最佳答案 我们发现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(数据,[:压缩]),我本可以省去一些麻烦.
感谢所有的意见和建议.非常感激!