以前學習了SpringCloud Bus結合MQ,沒有多學習MQ,本次學習相關內容,先了解異步,同步就不說了前端
異步: 客戶端非阻塞進程,服務端響應能夠是非即時的java
應用場景:
①通知類的服務->發出去便可,無需迴應;
②請求的異步響應->就是客戶端發送請求,服務端異步響應請求,客戶端不會產生阻塞且是默認響應,但不會馬上送達;
①②都屬於1對1交互模式;
③消息->能夠實現1對多的交互模式,好比發佈訂閱模式下,客戶端發佈消息通知,能夠被0到N個服務消費,再例如客戶端發送消息等待其餘服務的響應git
MQ在分佈式系統中都會用到的組件,仍是很重要的spring
應用場景:
①異步處理->好比用戶註冊的時候,須要手機(郵箱)驗證,有的平臺用戶註冊還能夠加用戶積分(經驗)獎勵,還有什麼身份證認證等等不少,這時候在用戶信息寫入數據庫後,能夠經過異步消息讓驗證服務或者獎勵各自執行各自的服務,提高效率,提高用戶體驗;docker
②流量控制->好比電商秒殺活動,秒殺時通常會由於流量忽然暴漲,過大流量致使服務掛掉,解決此問題,通常會在服務前端加入消息隊列,控制可容流量,若是消息隊列長度超過最大可容數量,須要丟棄額外的請求(或者跳轉其餘頁面)來控制流量,接着秒殺業務能夠根據消息隊列中有效的請求信息再作後續的處理;數據庫
③日誌處理->好比kafka消息隊列,其最初設計是爲了處理日誌,大數據中應用的比較多,當日志數據採集的時候,定時寫入kafka隊列,而後kafka對數據進行儲存,轉發等處理;app
④服務解耦->接着上面秒殺話題,假設用戶搶到,會有訂單order服務,商品product服務,用戶下單後,order服務須要通知product服務,若是order服務直接調用product服務的接口,這兩個服務之間是耦合的;那麼使用MQ,用戶下單後,order完成持久化並將消息寫入MQ隊列,返回order訂單完成,product服務訂閱MQ隊列中order的消息,採用推拉的方式獲取order下單信息,product服務根據order下單的信息,進行相關product商品的信息的變更(扣庫存),若是過程當中product服務不能正常執行,也不會影響order服務,由於order服務寫入MQ隊列以後,就不在關心其餘訂閱服務的後續操做了,這樣就現實了服務解耦;異步
就用order,product應用來作測試maven
order 服務分佈式
第一步老套路先引入maven依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
第二步yml配置仍是和上篇差很少,將rabbitmq的配置寫入了碼雲git倉庫裏,利用SpringCloud Bus讀取
spring: application: name: order cloud: config: discovery: enabled: true service-id: CONFIG profile: dev eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
但願碼雲git早點支持動態SpringCloud Bus,能用仍是能用,先用着,本身手動post請求好了
MQ接收方: 新建一個ReceiverMsg類,用來測試接收MQ的消息
package com.cloud.order.MQmsg; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; @Component @Slf4j public class ReceiverMsg { //此處註解指定去獲取名爲myQueue的queues隊列消息 @RabbitListener(queues = "myQueue") public void printMQ(String message){ log.info("【隊列消息】ReceiverMsg ,printMQ={}",message); } }
MQ發送方: 這邊直接寫在單元測試中,測試是否能成功,代碼以下
package order; import com.cloud.order.ServerApplication; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; //因爲以前對項目進行了項目多模塊化,運行單元測試的時候須要引導main啓動類 //沒有能夠不考慮classes = ServerApplication.class @SpringBootTest(classes = ServerApplication.class) @RunWith(SpringRunner.class) public class MQTest extends OrderApplicationTests{ //AmqpTemplate 操做MQ的API @Autowired private AmqpTemplate amqpTemplate; @Test public void send() { amqpTemplate.convertAndSend("myQueue","hello , MQ"); } }
RabbitMQ : 開啓docker中的rabbitmq,在http://192.168.99.100:15672/#/queues中新增一個名爲myQueue的隊列,用於上面測試
啓動服務,能夠看到有已經有兩個SpringCloudBus隊列了,一個是SpringCloud Config,一個是上面的order服務,註冊中心eureka一直都是開啓狀態
接着執行單元測試,在myQueue中的波動,說明有流量: ↓↓↓
調用方法中的print,也在控制檯中打印日誌 : ↓↓↓
按部就班,每次操做推拉隊列信息的時候,須要方法寫一下,rabbitmq面板中手動加一次,確定是很lower的
將ReceiverMsg類中的註解,改爲如下方式,便可自動批量建立Queue
@RabbitListener(queuesToDeclare = {@Queue("myQueue"),@Queue("myQueue2")})
啓動項目後,便可生成Queue
Exchange交換機,消息不直接發送到隊列,而是發送到了交換機,經過隊列綁定交換機轉給隊列
若是須要綁定Exchange,能夠改動註解
@RabbitListener(bindings = @QueueBinding( value = @Queue("myQueue"), exchange = @Exchange("MyExchange") ))
繼續order服務中,假設有不少賣方參與,賣奶茶的、賣mac的等等
不一樣賣方服務會發出不一樣的MQ消息,好比賣奶茶的只關心奶茶訂單、賣mac的只關心mac訂單,相互不關心其餘的組的信息,機子跑不動了,就模擬多服務處理方式 ↓↓↓
接收方:
@Component @Slf4j public class ReceiverMsg { @RabbitListener(bindings = @QueueBinding( key = "milkTea", value = @Queue("milkTeaOrder"), exchange = @Exchange("MyOrder") )) public void milkTeaMQ(String message){ log.info("【隊列消息】ReceiverMsg.milkTeaMQ ,milkTea={}",message); } @RabbitListener(bindings = @QueueBinding( key = "mac", value = @Queue("macOrder"), exchange = @Exchange("MyOrder") )) public void macMQ(String message){ log.info("【隊列消息】ReceiverMsg.macMQ ,macMQ={}",message); } }
測試 發送方:
@SpringBootTest(classes = ServerApplication.class) @RunWith(SpringRunner.class) public class MQTest extends OrderApplicationTests{ @Autowired private AmqpTemplate amqpTemplate; @Test public void sendMilkTea() { //第一個參數exchange; 第二個參數key; 第三個參數發送的msg amqpTemplate.convertAndSend("myOrder","milkTea","hello , milkTeaMQ"); } @Test public void sendMac() { amqpTemplate.convertAndSend("myOrder","mac","hello , macMQ"); } }
以上是RabbitMQ的基礎使用學習,還有不少高級內容,好比消息延遲處理,優先級等等
以後慢慢研究,有相關學習的同窗,能夠分享一下地址,Mark一塊兒學習學習,謝謝
----------------------------------------------------------------