Erlang二进制泄漏



我们有一个Erlang/Elixir应用程序(在18/ERTS 7.3.1上),该应用程序处理大型JSON有效载荷。

这是一个典型的工作流程:

  1. 听众从RabbitMQ获取令牌并发送到Gen_Server。

  2. gen_server将令牌放入带有未来时间(当前 n secs)的ETS表中。gen_server中的时间表工作将从ET中获取已过期的令牌,并使用这些令牌启动几个短期寿命。

  3. 这些简短的生命过程从Elasticsearch(使用Hackney)下载了30-50K JSON有效载荷,然后对其进行处理,然后将结果上传回Elasticsearch,然后该过程立即消失。我们跟踪这些过程,并确认它们死亡。我们每秒处理这些请求的5-10。

问题:我们看到了一个不断增长的二进制空间,在48小时内,这将成长为几个GB(通过观察者和调试印刷品见)。手动GC也没有影响。

我们已经添加了"侦察"并运行了侦察:bin_leak,但是这只会释放几个KB,并且对不断增长的二进制空间没有影响。

堆栈:Erlang 18/Erts 7.3.1,Elixir 1.3.4,Hackney 1.4.4,毒药2.2.0,Timex 3.1.13等,这些应用都不保存记忆。

过去有人遇到过类似的问题吗?会欣赏任何解决方案。

更新9/15/2017:

我们将应用程序更新为Erlang 19/Erts 8.3,Hackney and Poison Libs更新到了最新的,但仍然没有进展。这是Genserver中的一些日志,该日志使用Spawn/eception或send_after定期向其发送消息。在每个hander_info上,它都会抬高一个ETS表,如果找到任何"合格"条目,它会产生新的过程。如果不是,它只是返回{:noreply,state}。我们在输入该功能时(以KB)为单位,在此处打印VMS二进制空间信息,下面列出了日志。这是一天中的" Quit"时间。您可以看到二进制空间的逐渐增加。再次:conn.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倍的卷可以多年运行多年而没有问题或重新启动。我写了两个应用程序。

我们发现内存_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(数据,[:压缩])我可以保存一些头痛。

感谢所有输入和评论。非常感谢!

最新更新