Clojure + RabbitMQ /多线程消息消费

时间:2012-10-13 20:52:34

标签: multithreading clojure jvm rabbitmq langohr

上下文:Clojure + RabbitMQ(通过Langohr),跟进this question

我在使用来自RabbitMQ mq的消息时得到了奇怪的结果(在处理消息后从直接交换消息和发布到扇出交换)。我不明白为什么消息在消费过程中以单独的线程结束(线程切换发生的每一条消息)。

消费者在一个单独的线程中启动(以防止在发生任何IO异常时它崩溃主线程),但这并不能解释切换。

; Message handler
(defn message-handler
  [pub-name ch metadata ^bytes payload]
  (let [msg (json/parse-string (String. payload "UTF-8"))
        content (string/join " " (map msg '("title" "link" "body")))
        tags (pluck-tags content)]
    (println (format "HANDLER %s: Message: %s | found tags: %s"
                     (Thread/currentThread)
                     (msg "title")
                     (tags-to-csv tags)))
  (nil)))
  ; (lb/publish ch pub-name "" (json/generate-string (assoc msg "tags" (tags-to-csv tags))))))


(defn -main
  [& args]
  (let [conn          (rmq/connect {:uri (System/getenv "MSGQ")})
        ch            (lch/open conn)
        q-name        "q.events.tagger"
        e-sub-name    "e.events.preproc"
        e-pub-name    "e.events"
        routing-key   "tasks.taggify"]
    (lq/declare ch q-name :exclusive false :auto-delete false)
    (le/declare ch e-pub-name "fanout" :durable false)
    (lq/bind ch q-name e-sub-name :routing-key routing-key)
    (.start (Thread. (fn []
       (lcm/subscribe ch q-name (partial message-handler e-pub-name) :auto-ack true))))))

消息处理程序只打印出当前线程和收到的有效负载。这就是我得到的:

HANDLER in Thread[pool-1-thread-2,5,main]: Message: ...
HANDLER in Thread[pool-1-thread-2,5,main]: Message: ...
HANDLER in Thread[pool-1-thread-3,5,main]: Message: ... 
HANDLER in Thread[pool-1-thread-3,5,main]: Message: ...
HANDLER in Thread[pool-1-thread-3,5,main]: Message: ...
HANDLER in Thread[pool-1-thread-4,5,main]: Message: ...
HANDLER in Thread[pool-1-thread-4,5,main]: Message: ...

注意

我在玩代理时注意到了这一点。我想在自己的CPU绑定线程池中处理每个消息,并将其发布在无限(IO)线程池中。但是,在打印出当前线程后,我注意到即使不使用代理(或期货),消息也会被不同的线程处理。

2 个答案:

答案 0 :(得分:1)

1)你有一个扇出交换,这意味着在路由消息时根本不使用路由密钥。扇出交换将消息路由到绑定到它的每个队列。如果要使用路由密钥,请使用直接或主题交换。

2)您始终使用相同的队列名称,这意味着您的代码正在执行的操作只是将多个使用者添加到同一队列中。这意味着rabbitmq将围绕您的消费者传递信息。

答案 1 :(得分:0)

Langohr的作者。

代码中必定缺少某些内容。如果您使用代理获得此输出,那就是 easy:Clojure代理(也就是期货和承诺)使用线程池。 Langohr的langohr.consumers / subscribe或RabbitMQ Java客户端中的底层QueueingConsumer不会。