SpringCloud 微服務 (十) 消息隊列MQ 基礎

以前學習了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一塊兒學習學習,謝謝

 

----------------------------------------------------------------

相關文章
相關標籤/搜索