RabbitMQ多个工人模式

时间:2017-09-27 13:07:54

标签: go rabbitmq

我试图找到一个从输入队列异步使用的好方法,使用多个worker处理内容然后发布到输出队列。到目前为止,我已经尝试了很多示例,最近使用herehere中的代码作为灵感。

我目前的代码似乎并没有做到它应该做的事情但是,增加工人的数量不会提高性能(msg / s消耗或发布)并且goroutines的数量保持相当静态,而运行

主:

func main() {
    maxWorkers := 10

    // channel for jobs
    in := make(chan []byte)
    out := make(chan []byte)

    // start workers
    wg := &sync.WaitGroup{}
    wg.Add(maxWorkers)
    for i := 1; i <= maxWorkers; i++ {
        log.Println(i)
        defer wg.Done()
        go processor(in, out)
    }

    // add jobs
    go collector(in)
    go sender(out)

    // wait for workers to complete
    wg.Wait()
}

收集器基本上是来自RabbitMQ站点的示例,其中有一个goroutine,它从队列中收集消息并将它们放在&#39; in&#39;信道:

forever := make(chan bool)
go func() {
    for d := range msgs {
        in <- d.Body
        d.Ack(false)
    }
}()
log.Printf("[*] Waiting for messages. To exit press CTRL+C")
<-forever

处理器收到&#39; in&#39;和&#39; out&#39; channel,unmarshals JSON,执行一系列正则表达式,然后将输出放入&#39; out&#39;信道:

func processor(in chan []byte, out chan []byte) {

    var (
    // list of regexes declared here
    )

    for {
        body := <-in

        jsonIn := &Data{}
        err := json.Unmarshal(body, jsonIn)
        if err != nil {
            log.Fatalln("Failed to decode:", err)
        }

        content := jsonIn.Content

        //process regexes using:
        //jsonIn.a = r1.FindAllString(content, -1)

        jsonOut, _ := json.Marshal(jsonIn)

        out <- jsonOut
    }
}

最后,发件人只是RabbitMQ网站上的代码,建立连接,从&#39; out&#39;通道,然后发布到RMQ队列:

for {
    jsonOut := <-out

    err = ch.Publish(
        "",     // exchange
        q.Name, // routing key
        false,  // mandatory
        false,
        amqp.Publishing{
            DeliveryMode: amqp.Persistent,
            ContentType:  "text/json",
            Body:         []byte(jsonOut),
        })
    failOnError(err, "Failed to publish a message")

}

这是一种我会使用相当多的模式,所以我花了很多时间试图找到一些正常(并且很好)的东西 - 任何建议或帮助都会受到赞赏(如果不是很明显,我是Go的新手。

1 个答案:

答案 0 :(得分:0)

有一些事情突然爆发:

在主要功能中完成

wg.Add(maxWorkers)
for i := 1; i <= maxWorkers; i++ {
    log.Println(i)
    defer wg.Done()
    go processor(in, out)
}

defer返回时执行此处main,因此实际上并未指示处理何时完成。我不认为这会对你的程序的性能配置文件产生影响。

要解决这个问题,您可以将wg *sync.WaitGroup传递给processor,以便您的处理器可以指示何时完成。

CPU绑定处理

解析消息和执行Regex是一个CPU密集型工作负载。你的机器有多少个核心?如果在两台独立的机器上运行程序,吞吐量如何受到影响,吞吐量是否为2倍?如果你的内核数量加倍怎么办?如何使用1名工人和2名处理器工作人员运行程序?那双倍吞吐量?你是否最大化了你的rabbitmq本地实例?它是瓶颈吗?

设置基准测试和负载测试线束应该允许您设置实验以查看瓶颈的位置:)

对于基于队列的服务,很容易设置一个测试工具来填充rabbitmq,设置积压和基准测试处理这些消息的速度,或设置一个负载生成器发送x消息/秒给rabbitmq并观察你是否可以跟上。

rabbitmq能否很好地了解消息处理吞吐量?如果不是,我经常添加一个计数器去代码,然后记录一个间隔的整体平均吞吐量,以大致了解性能:

start := time.Now()
updateInterval := time.Tick(1 * time.Second)
numIn := 0
for {
    select {
    case <-updateInterval:
        log.Infof("IN - Count: %d", numIn)
        log.Infof("IN - Througput: %.0f events/second",
            float64(numIn)/(time.Now().Sub(start)).Seconds())
    case e := <-msgs:
        numIn++
        in <- d.Body
        d.Ack(false)
    }
}