生產者配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<rabbit:connection-factory id="connectionFactory"
host="10.153.25.15" username="insurance" password="insurance" port="5672" />
<rabbit:admin connection-factory="connectionFactory" />
<rabbit:queue id="queue_insurance" durable="true" auto-delete="false"
exclusive="false" name="queue_insurance">正常隊列當中指向死信
<rabbit:queue-arguments>
<entry key="x-message-ttl">設置超時
<value type="java.lang.Long">30000</value>
</entry>
<entry key="x-dead-letter-exchange">指定交換機
<value type="java.lang.String">alter</value>
</entry>
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:queue id="alter_queue" durable="true" auto-delete="false" exclusive="false" name="alter_queue"/>死信隊列
<rabbit:direct-exchange name="alter"
durable="true" auto-delete="false" id="alter">死信交換機
<rabbit:bindings>
<rabbit:binding queue="alter_queue" key="queue_key_insurance"/>
</rabbit:bindings>
</rabbit:direct-exchange>
<rabbit:direct-exchange name="exchange_insurance"
durable="true" auto-delete="false" id="exchange_insurance">正常交換機
<rabbit:bindings>
<rabbit:binding queue="queue_insurance" key="queue_key_insurance" />
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- (5)客戶端投遞消息到exchange。 -->
<rabbit:template id="amqpTemplate" exchange="exchange_insurance"
connection-factory="connectionFactory" />
</beans>
消費者配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<!-- 連接服務配置 -->
<rabbit:connection-factory id="connectionFactory2" host="10.153.25.15"
username="insurance" password="insurance" port="5672" />
<rabbit:admin connection-factory="connectionFactory2" />
<!-- queue 隊列聲明 -->
<!-- queue 隊列聲明 name 隊裏的額name 是關聯生產表和消費表的爲唯一線索 -->
<rabbit:queue id="queue_insurance" name="queue_insurance" >
<rabbit:queue-arguments value-type="java.lang.Long">
<entry key="x-message-ttl" value="30000"/>
</rabbit:queue-arguments>
</rabbit:queue>
<!-- 定義消費者監聽器 -->
<!-- 創建一個bean實例,bean實例中聲明處理請求的類 -->
<bean id="consumerLitener2" class="com.insurance.mq.CommissionController"></bean>
<rabbit:listener-container
connection-factory="connectionFactory2" acknowledge="auto" concurrency="8">
<!-- queues屬性從那個隊列中接收消息,ref屬性是當存在消息是使用哪個類去處理 -->
<rabbit:listener queues="queue_insurance" ref="consumerLitener2" />
</rabbit:listener-container>
</beans>
rabbitMq三種模式
一. Fanout Exchange 廣播
所有發送到Fanout Exchange的消息都會被轉發到與該Exchange 綁定(Binding)的所有Queue上。
Fanout Exchange 不需要處理RouteKey 。只需要簡單的將隊列綁定到exchange 上。這樣發送到exchange的消息都會被轉發到與該交換機綁定的所有隊列上。類似子網廣播,每臺子網內的主機都獲得了一份複製的消息。
所以,Fanout Exchange 轉發消息是最快的。
二. Direct Exchange 點對點
所有發送到Direct Exchange的消息被轉發到RouteKey中指定的Queue。
Direct模式,可以使用rabbitMQ自帶的Exchange:default Exchange 。所以不需要將Exchange進行任何綁定(binding)操作 。消息傳遞時,RouteKey必須完全匹配,纔會被隊列接收,否則該消息會被拋棄。
三. Topic Exchange 模糊匹配
所有發送到Topic Exchange的消息被轉發到所有關心RouteKey中指定Topic的Queue上,
Exchange 將RouteKey 和某Topic 進行模糊匹配。此時隊列需要綁定一個Topic。可以使用通配符進行模糊匹配,符號“#”匹配一個或多個詞,符號“*”匹配不多不少一個詞。因此“log.#”能夠匹配到“log.info.oa”,但是“log.*” 只會匹配到“log.error”。
所以,Topic Exchange 使用非常靈活。
mq也支持重發機制:
rabbitmq的消息確認機制分兩部分
一部分是生產端,一部分是消費端
生產端
有兩種選擇,transaction 和 confirm。confirm 的性能要好於transaction
//transaction 機制
channel.txSelect();
String msg = "msg test !!!";
for(int i=0;i<10000;i++){
msg = i+" : msg test !!!";
channel.basicPublish(EXCHAGE, QUEUE_NAME,null,msg.getBytes());
System.out.println("publish msg "+msg);
if (i>0&&i%100==0){
//批量提交
channel.txCommit();
}
} // 若出現異常 進行 channel.txRollback(),對相應批次的msg進行重發或記錄
channel.txCommit();
延遲隊列
AMQP和RabbitMQ本身沒有直接支持延遲隊列功能,但是可以通過以下特性模擬出延遲隊列的功能。
但是我們可以通過RabbitMQ的兩個特性來曲線實現延遲隊列:
RabbitMQ可以針對Queue和Message設置 x-message-tt,來控制消息的生存時間,如果超時,則消息變爲dead letter
RabbitMQ針對隊列中的消息過期時間有兩種方法可以設置。
- A: 通過隊列屬性設置,隊列中所有消息都有相同的過期時間。
- B: 對消息進行單獨設置,每條消息TTL可以不同。
如果同時使用,則消息的過期時間以兩者之間TTL較小的那個數值爲準。消息在隊列的生存時間一旦超過設置的TTL值,就成爲dead letter
RabbitMQ的Queue可以配置x-dead-letter-exchange 和x-dead-letter-routing-key(可選)兩個參數,如果隊列內出現了dead letter,則按照這兩個參數重新路由。
- x-dead-letter-exchange:出現dead letter之後將dead letter重新發送到指定exchange
- x-dead-letter-routing-key:指定routing-key發送
隊列出現dead letter的情況有:
- 消息或者隊列的TTL過期
- 隊列達到最大長度
- 消息被消費端拒絕(basic.reject or basic.nack)並且requeue=false
利用DLX,當消息在一個隊列中變成死信後,它能被重新publish到另一個Exchange。這時候消息就可以重新被消費。
設置方法:
- Per-Message TTL(官方文檔)
java client發送一條只能駐留60秒的消息到隊列:
byte[] messageBodyBytes = "Hello, world!".getBytes();AMQP.BasicProperties properties = new AMQP.BasicProperties();properties.setExpiration("60000");channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);
- Queue TTL
創建一個隊列,隊列的消息過期時間爲30分鐘
java client方式:Map<String, Object> args = new HashMap<String, Object>();args.put("x-expires", 1800000);channel.queueDeclare("myqueue", false, false, false, args);rabbitmqctl命令方式rabbitmqctl set_policy expiry ".*" '{"expires":1800000}' --apply-to queuesrabbitmqctl (Windows) rabbitmqctl set_policy expiry ".*" "{""expires"":1800000}" --apply-to queues11
- Dead Letter Exchanges設置方法(官方文檔)
channel.exchangeDeclare("some.exchange.name", "direct");Map<String, Object> args = new HashMap<String, Object>();args.put("x-dead-letter-exchange", "some.exchange.name");args.put("x-dead-letter-routing-key", "some-routing-key");channel.queueDeclare("myqueue", false, false, false, args);