我们有一个处理大型 json 有效负载的 erlang/elixir 应用程序(在 18/erts 7.3.1 上)。</p>
这是一个典型的工作流程:
侦听器从 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、poison 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}。我们在函数入口处打印 VM 二进制空间信息(以 KB 为单位),日志如下所示。这是一天中的“安静”时间。可以看到二进制空间逐渐增大。:recon.bin_leak(N) 或 :erlang.garbage_collect() 再次对这种增长没有影响。
11:40:19.896 [警告] 二进制 1: 3544.1328125
11:40:24.897 [警告] 二进制 1: 3541.9609375
11:40:29.901 [警告] 二进制 1: 3541.9765625
11:40:34.903 [警告] 二进制 1: 3546.2109375
--- 一些处理 ---
12:00:47.307 [警告] 二进制 1: 7517.515625
--- 一些处理 ---
12:20:38.033 [警告] 二进制 1: 15002.1328125
在我们的旧 Scala/Akka 应用程序中,我们从未遇到过这样的情况,该应用程序多年来处理 30 倍以上的运行量而没有出现问题或重新启动。我写了两个应用程序。