我有一个erlang gen_server,它以异步方式从客户端接收消息(使用强制转换)。在每个消息处理中,服务器将它们插入到有序的ETS表中并根据条件删除其中的一些(由于条件删除,ETS表中的记录数量大部分时间在5000左右。但是很少见可以将此大小增加到200k的场景,为插入和删除引入了开销。)
这种工作正常,直到每秒的消息数为100k但超过此值时,它会给我进程内存高水印并开始消耗大量内存。当我将插入和删除部分注释到有序的ets时,它可以每秒处理超过100k。你能给我一些关于如何解决这个问题的提示吗?
进程可以分配的内存最大限制是多少?我正在使用35 GB的内存,我将水印阈值设置为memsup:set_procmem_high_watermark(0.6)
。我也试过gbtree和有序字典,但是他们没有解决内存错误。
答案 0 :(得分:1)
我有个建议。当它超过100k / s时,gen_server无法及时处理消息队列,因此它开始增长=> gen_server变慢并且内存泄漏。如果它增长,请尝试监控erlang:process_info(Pid, message_queue_len)
。
答案 1 :(得分:0)
Erlang中没有这样的选项。 memsup:set_procmem_high_watermark/1
只是设置进程内存分配的阈值。如果超过阈值,则会发出警报。
一开始你必须找出你的流程为什么会变慢的原因。如前所述,检查消息队列的特征:它是否随着时间的推移而增长?如果是这种情况,您的流程将无法按照到达的速率处理邮件。 erlang:process_info/2
会有所帮助。
要记住的另一件事是当您在ETS中插入/查找数据时,会复制对象。因此,如果删除对象时必须满足的条件涉及从ETS检索数据,那么也可能导致您的问题。
有几种方法可以解决这个问题。显而易见的一个是简单地使用背压机制,例如,让客户端同步发送消息。
你可以尝试将你的一个进程分成几个进程。为实现这一目标,您可以根据消息中包含的某些信息,让一个进程将消息分发给其他人。
最后,您可以尝试对您的ETS应用一些优化。例如,如果您要存储大型对象,则可以检查是否没有不必要地检索它们(使用ets:lookup/X
代替ets:match/X
或ets:match_object/X
来获取您的位数希望从存储的消息)。