RabbitMq學習:
1.概念:rabbitMq是基於amqp的高級協議,運行速度和socket一致。
2.核心組件:
broker:服務器(server)
exchange:
1.direct:直接匹配
2.topic:模糊匹配
#:關鍵字後面多詞模糊匹配
*: 關鍵字後面只匹配一個詞
通常是消費者這邊使用通配符的匹配生產者
3.fanout:不需要處理路由件,不走任何的路由key,會將消息發送到指定交換機的指定queue上。
性能最好,因爲不走路由
channel:通道,所有操作都在通道完成
message: 由兩部分組成:properties(消息設置)、body(具體內容)
queue:
routingkey:
virtual host:虛擬地址,用於邏輯隔離,最上層的消息路由。同一個virtual host中不能夠有相同名字的exchange或者queue
3.提供者和消費者
提供者:只關心exchange和routingKey
消費者:只關心queue和routingKey以及exchange0
如果消息提供者沒有指定exchange的話,就會默認使用AMQP DEFAULT exchange 根據routingKey去完全匹配一個queue,
如果能夠匹配就將消息路由出去,否則刪除message。
4.消息可靠性投遞方案
1.消息入庫機制,在發送消息之前,將消息入庫並這隻狀態爲發送中。消息正常發送到rabbit server並返回confirm,將數據庫消息發送狀態爲完成。設置分佈式任務等待server的confirm返回值,如果在規定的時間沒有返回值則重新retry 發送消息。在規定的次數內完成發送並收到server的confirm返回值,將數據庫狀態設置爲完成。如在規定的次數未完成,則將數據庫消息發送狀態設置爲失敗。後期全部發送完畢之後統一處理(日誌信息顯示失敗原因!rpc調用會出現網絡原因)
2.延遲發送:消息提供者首先入庫消息的部分信息,同時起連個發送服務,一個立即發送,一個延時發送(具體延時時間看具體情況)新建一個callback listener監聽消費者端發送回來的confirm messge以及提供者延時發送的消息,如果能夠監聽到,則將這條信息入庫。如果不能夠監聽到則提示提供者重新發送信息。當延時發送的消息被監聽到,回去數據庫中查詢是否要這條消息的消費記錄,如果有則不運行這條延時發送的消息,如果在規定的時間中依然沒有這條消息的消費記錄,則消費延時消息。
5.如何避免消息的重複消費?
使用消息提供者端的comfirm listener來監聽消息返回值。
返回值爲ack or noack
6.如何判斷消息提供者提供的消息是否被消費?
使用return listener來監聽消息是否被消費。
7.自定義consumer extends DedfaultConsumer就能夠實現消費了。
8.消費端的限流處理方式:
爲什麼要進行消費端限流?
巨量的消息推送過來,單個客戶端無法同時處理這些海量的數據,可能會導致客戶端宕機,故需要進行消費端限流配置。RabbitMq提供了一種qos功能,在非自動確認消息的前提下,如果一定數目的消息未被確認前,不進行消費新的消息
原生api:defaultConsumer.basicqos(int perfetchSize,int perfetchCount,bollean gloal)
perfetchSize: 0 表示不指定上限,其他的數字表示指定上限。
perfetchCount:表示客戶端(消費者端)能夠同時接收的最大消息數量
gloal: true 便是針對整個channel,faalse針對的是 consumer
注意事項:要想使用qos進行限流,必須將ack設置爲手動ack
Demo:
/**
* 聲明一個exchange
*/
channel.exchangeDeclare(exchangeName,exchangeType,true);
/**
* 聲明一個隊列
*/
channel.queueDeclare(queueName,true,false,false,null);
channel.queueBind(queueName,exchangeName,routingKey);
/** 指定提供者的數量 指定同時過來多少條,其餘的要等到這些ack後再過來
是否全局化true針對channel false consumer
* int prefetchSize, int prefetchCount, boolean global
*/
channel.basicQos(0,3,false);
DefaultConsumer consumer = new MyConsumer(channel);
/**
* String queue, boolean autoAck, Consumer callback
*/
channel.basicConsume(queueName,false,consumer);
9.ack和手動ack
ack是消費者是否成功消費消息的標識,其中關鍵配置參數爲:Boolean autoAck true = 自動ack false=手動ack
provider可以用 confirm listener來監聽消息是否被消費,同時給出相關處理。
手動ack需要在自定義的消費者中,直接根據某個條件來判斷其是否ack。
basicAck() 爲成功消費消息!
basicNack() 手動消費失敗!
10.死信隊列 dlx dead letter exchange
什麼情況下消息會進入死信隊列?
1.消息沒有被成功消費,同時在手動nack處理時參數requeue被設置爲false,這時候消息會進入死信隊列。
2.消息時間過期,TTL過期,超過設置的最大消息存活時間。
3.超過設置qos中的最大隊列數:perftchSize
死信隊列的聲明:在消費端聲明,和其他的交換機聲明方式一致。死信隊列數據存放在隊列裏面。
11.自定義adpter中必須實現一個默認方法名:handleMessage
12.springboot 註解接收消息:
@RabbitHandler
@RabbitListener(指定queue、指定exchange、指定routingkey)
onmessage(@Payload 目標屬性 @Headers 需要的屬性內容)
從properties裏面讀取數據只需要使用${springboot.rabbitMq.exchange.name} 表達式形式處理就ok了
13.集羣的恢復。
1.正常的A、B(b爲master)關閉停機。
先啓動A,30s後啓動B。或者先啓動B再啓動A即可。
2.A B同時停機(機房掉電等原因)。
只需要在30s內啓動A B兩個節點即可。
3.A(備用節點)掛了,B(主節點)沒有掛。
啓動B(主節點),然後再主節點上執行rabbitmqctl forget_cluster-node-A 解除A節點和本集羣的關係,然後再新啓動一個節點作爲從(備)節點加入到該集羣即可
4.A(備用節點)沒掛,B(主)節點掛掉了。
先啓動A節點,然後再A節點上啓動命令:rabbitmqctl forget_cluster-node-B_offline 就可以在主節點不在線的情況下解除主節點和該集羣的綁定,然後再將A作爲主節點,最後新啓動一個新的節點作爲從節點加入該集羣即可。