akka演员之间的工作量平衡

时间:2015-06-02 20:27:22

标签: multithreading scala web-crawler akka actor

我有2个用于抓取链接的akka​​演员,即查找第X页中的所有链接,然后查找从X等链接的所有页面中的所有链接...

我希望他们以相同的速度或多或少地前进,但往往其中一人变得饥饿而另一人消耗所有资源。

我尝试过以下方法(简化)。 单页抓取由以下actor完成:

$('.your-form').trigger($.extend($.Event('submit'), { parsley: true }))

方法1:

class Crawler extends Actor {
  def receive = {
    case Crawl(url, kind) =>
      // download url
      // extract links
      sender ! Parsed(url, links, kind)
  }
}

方法2:

class Coordinator extends Actor {
  val linksA = ...
  val linksB = ...
  def receive = {
    case Parsed(url, links, kind) =>
      val store = if (kind == kindA) linksA else linksB
      val newLinks = links -- store
      store ++= links
      newLinks.foreach { link =>
        val crawler = context.actorOf(Props[Crawler])
        crawler ! Crawl(link, kind)
      }
  }
}

第二种方法使事情稍好一些,但没有完全修复它。

是否有一种很好的方法可以使这两种爬行器以相同的速度或多或少地进步?我应该在它们之间发送消息吗?依次解锁对方?

2 个答案:

答案 0 :(得分:2)

我正在开发一个类似的程序,其中工作人员的资源成本不均匀(在我的情况下,任务是执行数据库查询并将结果转储到另一个数据库中,但就像抓取不同的网站会有不同的成本所以不同的查询也会有不同的成本)。我采用的两种处理方式:

  1. RoundRobinRouter替换为SmallestMailboxRouter
  2. 不要让Coordinator一次发送所有邮件 - 而是将它们分批发送出去,如果你有十个工作人员,那么发送四十条邮件应该让他们最初保持忙碌。每当工作人员完成任务时,它就会向Coordinator发送一条消息,此时Coordinator会发送另一条消息,该消息可能会发送给刚刚完成其任务的工作人员。 (您也可以批量执行此操作,即在收到n“任务完成”消息后,Coordinator会发送另外的n条消息,但不要使n过高或者一些任务极短的工人可能会闲着。)
  3. 第三种选择是欺骗并在所有参与者之间共享ConcurrentLinkedQueue:在填充队列后,Coordinator向工作人员发送“开始”消息,然后工作人员轮询队列直到它空。

答案 1 :(得分:1)

我还考虑使用工作拉动模式。这里很好地描述了它,例如:"Akka Work Pulling Pattern to prevent mailbox overflow, throttle and distribute work"。 来自Zim-Zam的方式#2基本上采用相同的方法。

因此,当新的已解析链接可用时,您可以立即宣布所有内容都可用,而不是立即将所有任务“推送”到您的抓取工具,然后他们会在准备就绪时“拉动”该工作。

此外,在协调员方面,您可以添加一些更复杂的逻辑,以便在需要时优先处理某些链接类型(例如,使用PriorityQueue作为待处理链接)。

使用SmallestMailboxRouter会使事情稍微更好,但实际上它仍然基于“推动”方法。