我们有一个 erlang/elixir 应用程序(基于18/erts 7.3.1),它会处理大量的 json 负载。以下是典型的工作流程:
1. 监听器从 rabbitmq 获取令牌并将其发送到 gen_server。 2. gen_server 将令牌插入 ETS 表中并设置过期时间(当前时间 + n 秒)。gen_server 中的定时任务会从 ETS 中获取过期的令牌,并使用这些令牌启动多个短暂的进程。 3. 这些短暂的进程使用 hackney 从 elasticsearch 下载30-50k的 json 负载并进行处理,然后将结果上传回 elasticsearch,最后立即终止进程。我们每秒处理5-10个此类请求。
问题:我们发现二进制空间不断增长,在48小时内增长到几个 GB(通过 observer 和 debug prints 观察到)。手动进行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等,这些应用都没有占用内存。
是否有人遇到过类似的问题?我们会非常感谢任何解决方案。
更新 9/15/2017:
我们将应用程序更新到 Erlang 19/ERTS 8.3,并将 hackney 和 poison 库更新到最新版本,但仍然没有进展。以下是一个 GenServer 中的日志,该 GenServer 定期向自己发送消息,使用 spawn/receive 或 send_after。每次 handle_info 调用时,它都会查找 ETS 表,如果找到任何“符合条件”的条目,则会生成新的进程。否则,它只会返回 {:noreply, state}。我们在函数入口处打印VM的二进制空间信息(以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
1. 监听器从 rabbitmq 获取令牌并将其发送到 gen_server。 2. gen_server 将令牌插入 ETS 表中并设置过期时间(当前时间 + n 秒)。gen_server 中的定时任务会从 ETS 中获取过期的令牌,并使用这些令牌启动多个短暂的进程。 3. 这些短暂的进程使用 hackney 从 elasticsearch 下载30-50k的 json 负载并进行处理,然后将结果上传回 elasticsearch,最后立即终止进程。我们每秒处理5-10个此类请求。
问题:我们发现二进制空间不断增长,在48小时内增长到几个 GB(通过 observer 和 debug prints 观察到)。手动进行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等,这些应用都没有占用内存。
是否有人遇到过类似的问题?我们会非常感谢任何解决方案。
更新 9/15/2017:
我们将应用程序更新到 Erlang 19/ERTS 8.3,并将 hackney 和 poison 库更新到最新版本,但仍然没有进展。以下是一个 GenServer 中的日志,该 GenServer 定期向自己发送消息,使用 spawn/receive 或 send_after。每次 handle_info 调用时,它都会查找 ETS 表,如果找到任何“符合条件”的条目,则会生成新的进程。否则,它只会返回 {:noreply, state}。我们在函数入口处打印VM的二进制空间信息(以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 [警告] 二进制1:15002.1328125
我们在旧的Scala / Akka应用程序中从未遇到过这样的情况,该应用程序处理的数量是当前应用程序的30倍。旧应用程序在多年运行后也没有出现任何问题或重启。我编写了这两个应用程序。
binary:copy/1
复制每个二进制,并转换结构。当然,这会导致性能下降,但请观察漏洞是否仍存在。如果它消失了,那么您就知道问题是保留子二进制到原始JSON中,您可以进一步调查。这是验证您假设的好方法。 - Hynek -Pichi- Vychodilbinary:copy/1
函数的原因。 - zxq9