消息隊列的使用場景和使用技巧

1、消息隊列的使用場景

一、應用解耦

假設商品和結算和支付是不一樣的系統,兩個系統之間的通信能夠經過消息隊列完成,不須要強制性的接口關聯。值得注意的是消息隊列中間件通常都支持同步和異步操做。java

 

二、高併發的異步處理

一個http請求裏面若是有多線程的異步操做的話,在高併發環境下回產生大量的等待隊列,形成後果是大量的線程被佔用,內存,cup,數據庫等都會處於高負荷狀態。redis

經過消息隊列中間件將異步處理都發送到消息隊列中,而後經過推或者拉的方式執行異步處理的內容,減小了線程的佔用,也不會在請求系統中產生大量等待隊列,由於實際生產環境消息隊列中間件都會獨立一臺或者多臺服務器。算法

三、流量削鋒

主要用於高併發業務場景好比秒殺。spring

將用戶請求放入消息隊列中,若是消息隊列的大小超過了設置的最大值,則直接拋棄改請求。數據庫

四、日誌系統

不少系統多會在aop層保存日誌到mongo,若是是同步操做會嚴重影響請求響應時間,即便經過線程來達到異步操做的目的也會暫用網站的大量資源,經過mq保存日誌,用獨立的日誌系統進行日誌處理會是一個好的辦法,若是設計的好的話日誌系統甚至能夠兼容多個平臺。apache

五、信息變動通知

假設商品信息均保存到了redis中,若是商家後臺對商品信息進行了修改,可經過發送消息的方式告知商品信息已變動,消費端只須要經過監聽去修改響應redis中商品信息接口。json

六、即便通信場景

經過消息隊列實現聊天。緩存

七、數據同步

在實際業務中數據庫的部分字段多是冗餘字段,或者說冗餘字段的值是其它表幾個字段的值的和,此種場景數據同步可經過mq來實現數據同步,以避免相關字段的保存修改操做接口顯得不三不四服務器

 

2、消息隊列的使用技巧(舉例用activemq)

一、預防消息丟失

1)對於重要業務最好在redis裏面保存一份copysession

2)消息回執,制定檢查機制,肯定消息 已經被執行

3)定時器,查漏補缺,特別是數據同步,緩存設置等場景

 

二、使用隊列應該先肯定是使用一對一模式仍是一對多模式

部分業務多是但願多個平臺不一樣的項目多能幹收到消息,應使用發佈訂閱模式。

有些業務涉及併發,可能須要要求一對一關係,須要控制。

三、消息隊列的推模式是經過監聽器來完成的,監聽器一次能夠監聽多個通道

以java舉例

<bean id="myDestination" class="org.apache.activemq.command.ActiveMQTopic">  
        <!-- 設置消息主題的名字,多個用逗號隔開 -->  
        <constructor-arg index="0" value="chanel1,channel2,channel3,channel4" />  
    </bean>  
    <!-- 消息監聽容器 -->  
    <bean id="listenerContainer"    
        class="org.springframework.jms.listener.DefaultMessageListenerContainer">    
        <property name="connectionFactory" ref="mqFactory" />    
        <property name="destination" ref="myDestination"/>    
        <property name="messageListener" ref="messageDelegateListenerImpl" />    
        <property name="pubSubDomain" value="true" /> 
         <property name="pubSubNoLocal" value="false" /> 
        
        
    </bean>

 

四、發送textMessage

發送消息最好發送textMessage,若是是對象將對象轉換爲json字符串便可,由於textMessage能夠直接在控制檯發送,方便本身調試和測試人員進行測試。

/**
	 * 發佈消息
	 * 
	 * @param channel
	 * @param message
	 * @date 2016年7月19日
	 */
	public static void sendTopic(String channel, Object message) {
		String messageStr = "";
		if (message.getClass().isAssignableFrom(String.class)) {
			messageStr = (String) message;
		} else {
			messageStr = JsonUtil.objectToJsonStr(message);
		}
		final String finalMessage = messageStr;
		try {
			final Topic destination = publishJmsTemplate.getConnectionFactory().createConnection().createSession(false,Session.AUTO_ACKNOWLEDGE).createTopic(channel);
			publishJmsTemplate.send(destination, new MessageCreator() {
				public Message createMessage(Session session) throws JMSException {
					log.info("topic name is" + destination.toString() + ",publish content is:\n" + finalMessage);
					TextMessage textMessage = session.createTextMessage(finalMessage);
					textMessage.setJMSExpiration(TimeUnit.DAYS.toSeconds(1));//發佈的消息保留一天
					return session.createTextMessage(finalMessage);//text message 在mq控制檯也能夠發,便於測試和維護
				}
			});
		} catch (Exception e) {
			log.error("--------------添加生產隊列對象失敗" + e.toString(), e);
		}
	}

如圖,activemq控制檯僅容許發送textMessage

五、可經過設置多個通道來提升消息消費的效率

方案是編寫算法將消息路由到設置好的不一樣渠道,須要注意的是多渠道消費消息可能出現併發問題,注意控制,能夠將同一類型的消息或者相同的消息發送到同一個渠道,經過算法去控制併發的問題。

相關文章
相關標籤/搜索