你可以溢出Erlang进程的消息队列吗?

时间:2014-12-17 12:41:32

标签: erlang

我仍处于Erlang的学习中,所以我可能错了,但这就是我理解进程'消息队列的方式。

进程可以在它的主接收循环中,接收某些类型的消息,而稍后它可以被置于等待循环中以处理第二循环中的不同类型的消息。如果进程将在第二个循环中接收用于第一个循环的消息,它只会将它们放入队列中,暂时忽略它们,并且只处理它在当前循环中可以匹配的消息。现在如果它再次进入第一个接收循环,它将从头开始并再次处理它可以匹配的消息。

现在我的问题是,如果这是Erlang的工作原理并且我理解正确,那么当恶意进程发送一堆进程永远不会处理的消息时会发生什么。队列最终是否会溢出,导致进程崩溃或我应该如何处理?我会输入一个例子来说明我的意思。

现在,如果恶意程序获得了Pid并且会反复进行Pid ! {malicioudata, LotsOfData},那么这些消息是否会被过滤掉,因为它们永远不会被处理,或者它们是否只是在队列中堆叠?

startproc() -> firstloop(InitValues).

firstloop(Values) ->
  receive
    retrieveinformation ->
      WaitingList=askforinformation(),
      retrieveloop(WaitingList);
    dostuff ->
      NewValues=doingstuff(),
      firstloop(NewValues);
    sendmeyourdata ->
      sendingdata(Values),
      firstloop(Values)
  end.

retrieveloop([],Values) -> firstloop(Values).
retrieveloop(WaitingList,Values) ->
  receive
    {hereismyinformation,Id,MyInfo} ->
      NewValues=dosomethingwithinfo(Id,MyInfo),
      retrieveloop(lists:remove(Id,1,WaitingList),NewValues);
  end.

2 个答案:

答案 0 :(得分:2)

消息计数没有硬限制,并且没有固定数量的内存限制,但如果你有数十亿条消息(或者一些超级巨大的消息,你可能肯定会耗尽内存) )。

在OOM之前,由于一个巨大的邮箱,你会注意到selective receives taking a long time(不是“选择性接收”是一个很好的模式可以跟随大部分时间...)或无辜地窥视进程邮件队列和realized you've opened Pandora's Box in your terminal

这通常被视为Erlang世界中的限制和监控问题。如果您无法跟上并且您的问题可以并行化,那么您需要更多的工作人员。如果您的硬件最大化,那么您需要更高的效率。如果你仍在最大化你的硬件,不能再获得更多,而你仍然不知所措,那么你需要决定如何实现回击或减载。

答案 1 :(得分:1)

不幸的是,没有"消息队列溢出"并且它会一直增长,直到因内存分配错误导致VM崩溃。

解决方案是在主循环中删除任何无效消息,因为您不会因为阻止过程的性质而接收{hereismyinformation, _,_}中的任何一个,也不会接收askforinformation()中的任何消息。

startproc() -> firstloop(InitValues).

firstloop(Values) ->
  receive
    retrieveinformation ->
      WaitingList=askforinformation(),
      retrieveloop(WaitingList, Values); % i assume you meant that
    dostuff ->
      NewValues=doingstuff(),
      firstloop(NewValues);
    sendmeyourdata ->
      sendingdata(Values),
      firstloop(Values);
    _ -> 
      firstloop(Values) % you can't get {hereismyinformation, _,_} here so we can drop any invalid message
  end.

retrieveloop([],Values) -> firstloop(Values).
retrieveloop(WaitingList,Values) ->
  receive
    {hereismyinformation,Id,MyInfo} ->
      NewValues=dosomethingwithinfo(Id,MyInfo),
      retrieveloop(lists:remove(Id,1,WaitingList),NewValues);
  end.

对于意外消息来说,这并不是一个问题,因为它很容易避免,但是当进程队列的增长速度超过了它的处理速度时。对于这个特定问题,生产系统有一个很好的jobs framework