我们有一个Erlang/Elixir应用程序(在18/ERTS 7.3.1上),该应用程序处理大型JSON有效载荷。
这是一个典型的工作流程:
-
听众从RabbitMQ获取令牌并发送到Gen_Server。
-
gen_server将令牌放入带有未来时间(当前 n secs)的ETS表中。gen_server中的时间表工作将从ET中获取已过期的令牌,并使用这些令牌启动几个短期寿命。
-
这些简短的生命过程从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(数据,[:压缩])我可以保存一些头痛。
感谢所有输入和评论。非常感谢!