我遇到了问题,我使用gen服务器做了一些简单的工作:
one handle_cast to do a long time work(takes 60 seconds)
one handle_cast to do a very fast work
流量低时,一切都很好。但是当服务器进程正在进行第一次长时间工作并且客户端向服务器发送数千条消息(例如邮箱中的1000000条消息)时,长时间的工作将变得极其缓慢,可能需要600秒才能完成。
问题就像stackoverflow In Erlang, when a process's mailbox growth bigger, it runs slower, why?上的这个问题一样。
但我仍然不明白。如果是因为垃圾收集,垃圾收集怎么会花这么长时间?
答案 0 :(得分:1)
如果您有一个具有如此大邮箱的进程,则您的系统可能在设计中出错。
因为所有流量都经过一个流程而且会成为瓶颈。
Erlang的一个主要想法是,创建新流程既快又便宜,所有交易都应该有自己的流程。
只有在这些事务应具有对某些共享资源的序列化访问权限的地方(通常是对某些ETS表的更新),才需要对所有事务执行一个进程。此序列化访问(使用消息)应尽可能短。
答案 1 :(得分:0)
这不是因为你正在使用一个句柄转换,使得转换中的代码没有阻塞,只释放客户端的接口,因此它不会等待请求完成。
因此,如果请求需要60秒才能完成,您必须从服务器生成一个单独的进程来处理它。这是能够继续处理新传入消息的唯一方法。
一个新的潜在问题出现了:是否可以在MongoDB中与文档插入并行处理新请求?
如果是,一切都很好,
如果不是,那么您将不得不修改您的设计,例如,向请求与数据库插入不兼容的任何客户端返回否定确认(如果可能,请忽略请求)。你必须尽快清空邮箱,在60秒内累积邮件不是一个好的选择,你正在推动erlang远远超出其正常使用范围,想象你的用例:
答案 2 :(得分:0)
最后,我在this paper
中找到了答案第3节。 erlang的内存架构以流程为中心。每个进程分配和管理自己的内存区域,通常包括PCB,专用堆栈和私有堆。
这导致了缺点:高内存碎片
即使该存储区域中存在大量未使用的空间,进程也不能利用另一进程的存储器(例如堆)。这通常意味着默认情况下进程只能分配少量内存。这反过来通常会导致对垃圾收集器的大量调用。
如此庞大的邮箱大小会导致整个系统变慢。
但是,这仍然不是重点。按照@pascal的好评,处理数据库的长时间成本,我忽略了gen_sever是关于发送和接收的全部。我遇到了gen_sever:在gen打电话,显然有选择性接收!原谅我只是尝试一下erlang〜