精通RabbitMQ之Exchange和路由分發
精通RabbitMQ之Exchange和路由分發
交換機
交換機的責任主要在於路由分發生產者的訊息到佇列中,一個Exchange可以binding多個Queue,一個Queue可以同多個Exchange進行binding。
預設交換機
前面我們聊過,我們在簡單的使用過程中甚至可以不宣告交換機,但這並不意味者rabbitmq可以沒有exchange工作。我們不申明是因為rabbitmq提供的預設交換機。
預設交換機(default exchange)實際上是一個由rabbitmq預先宣告好的沒有名字(名字為空字串)的直連交換機(direct exchange)。
這裡我借用官方的一個說明來說明預設交換機。當我們聲明瞭一個名為search-indexing-online
的佇列,rabbitmq會自動將其繫結到預設交換機上,繫結(binding)的路由鍵名稱也是為search-indexing-online
。因此,當攜帶著名為search-indexing-online
的路由鍵的訊息被髮送到預設交換機的時候,此訊息會被預設交換機路由至名為search-indexing-online
的佇列中。換句話說,預設交換機看起來貌似能夠直接將訊息投遞給佇列,儘管技術上並沒有做相關的操作。
那麼除了預設交換機,還有那些可以使用的交換機嗎?
還記得我們上面虛擬主機和使用者篇新建的test虛擬主機和test使用者,我們登入進去,看看rabbitmq提供給的預設交換機和其他交換機。
有沒有發現,我們新建的虛擬環境裡面除了有預設交換機還有amq開頭的系統交換機,我們這裡並不關心繫統交換機的用途,我們重點關注有哪幾種交換機。
從上圖我們可以看出來,有direct /fanout /headers/topic
四種(預設交換機是direct型別),OK,我們接下來聊一聊其他種類的交換機。
直連交換機
直連型交換機(direct exchange):字面意思已經很好理解了,更好的可以理解為交換機和佇列通過routingKey
topic
的模糊匹配,直連型交換機是精確匹配的,假設我麼指定了routingKey
是test
的話,那麼直連型交換機只會將routingKey
是test
的投遞到佇列,而不會投遞類似於test的訊息(例如 test1)。儘管交換機和佇列通過routingKey
是一一對應的,但是它也可以處理多播路由將同一個訊息多播路由到同一個routingKey
的多個佇列。
為了說明直連交換機,我們可以看看下面的案例:
這裡我們先回顧一下,上面說過的,一個Exchange
可以binding
多個Queue
,一個Queue
可以同多個Exchange
進行binding
。這裡我覺得大家要有一個明確的概念,Exchange
和 Queue
是沒有從屬關係的,它們之間只是通過routingKey
來繫結的關係。然後我們再回到這個案例,我們有一個直連交換機X,它和2個佇列之間建立的關聯,X和Q1 之間是我們最常配置的直連交換機的用法,但是實際上一個佇列可以多個binding和direct直連交換機繫結。例如Q2,這樣實際意義上我們不怎麼會用,這裡主要讓大家理解用法。
我們繼續看下一個案例:
這裡我們還可以用同一個bindingKey
來把多個queue
繫結到同一個exchange
,這個時候我們的直連交換機就相當於一個多播路由的fanout
交換機。
廣播交換機
廣播交換機(funout exchange) 將訊息路由給繫結到它身上的所有佇列,而不理會繫結的路由鍵。如果N個佇列繫結到某個廣播交換機上,當有訊息傳送給此廣播交換機時,交換機會將訊息的拷貝分別傳送給這所有的N個佇列。廣播交換機用來處理訊息的廣播路由(broadcast routing)。
廣播路由器我覺得是最好理解的,因為它無視了routingKey,只要有佇列與之關聯,它就會將訊息的Copy投遞到佇列。現實開發中,如果我們有需要將訊息投遞到多個系統可以考慮廣播路由。
主題交換機
主題交換機(topic exchanges) 是我們使用的最多最普遍效能最好的交換機,主題交換機通過對訊息的路由鍵和佇列到交換機的繫結模式之間的匹配,將訊息路由給一個或多個佇列。主題交換機經常用來實現各種分發/訂閱模式及其變種。主題交換機通常用來實現訊息的多播路由(multicast routing)。
我們把訊息投遞到topic
交換機的時候一般需要指定一系列由點號連線單詞的字串的routingKey
,同時我們在繫結訊息佇列和交換機的時候也需要指定一系列由點號連線單詞的字串的routingKey
。
當生產者投遞了確定routing key
的訊息將會被topic
交換機推送給所有能與routing key
匹配的佇列。我們這裡需要注意它們之間的匹配規則:
● *(星號):可以(只能)匹配一個單詞
● #(井號):可以匹配多個單詞(或者零個)
這裡需要注意的是單詞
,而不是字元
,並且它們是通過.
連線。
我們還是一樣,看個案例:
*.orange.* 的路由規則只能匹配由3個單片語成,並且中間的單詞是orange
*.*.rabbit 的路由規則只能匹配由3個單片語成,並且最後的單詞是rabbit
lazy.# 的路由規則沒有詞數限制,但是要求首單詞必須是lazy
下面我們給出幾個路由鍵,大家理解一下它的分發規則:
lazy Q2可以匹配
hardworking.black.turtle 無匹配
lazy.orange.rabbit Q1 Q2都可以匹配,Q2的兩個路由規則都匹配了,但是同一條訊息只會被推送到Q2上一次
lazy.orange.rabbit.try 只有Q2可以匹配(注意詞數限制)
hardworking.orange.rabbit Q1可以匹配
lazy.white.rabbit Q2可以匹配(但是隻會匹配lazy.#規則)
Topic
型別的exchange
是很強大的,也很有趣,我們其實可以使用它的變體來實現其它型別的exchange。
● 當一個佇列和exchange繫結的routingKey為”#”時,它將會接收所有的訊息,此時和fanout型別的exchange很像。
● 當一個佇列和exchange繫結的routingKey為不包含”*”和”#”時,這時候就很像direct型別的exchange。
頭交換機
頭交換機(headers exchange):有時訊息的路由操作會涉及到多個屬性,此時使用訊息頭就比用路由鍵更容易表達。頭交換機使用多個訊息屬性來代替路由鍵建立路由規則。通過判斷訊息頭的值能否與指定的繫結相匹配來確立路由規則。(效能不好,幾乎不用,我們這裡不討論,大家就知道還有這個東西就好了)。