SpringCloud前置知識+RabbitMQ

1、微服務架構介紹

1.單體架構

​ 單體架構也被稱爲單體應用,它是將全部的功能模塊所有耦合在一個項目中css

1.1 單體架構特色

​ 1.最終會被打包成一個獨立的單元(一個惟一 的jar包或war包)html

​ 2.會以一個進程的方式來運行前端

1.2 單體架構的優勢與缺點

優勢java

  • 項目易於管理
  • 部署簡單

缺點node

  • 測試成本高
  • 可伸縮性差
  • 可靠性差
  • 迭代困難
  • 跨語言程度差
  • 團隊協做難

2.微服務架構

2.1 什麼是微服務

微服務是一種架構風格。一個大型的複雜軟件應用,由一個或多個微服務組成。系統中 的各個微服務可被獨立部署,各個微服務之間是鬆耦合的。每一個微服務僅關注於完成一件任 務並很好的完成該任務。c++

2.2 常見的架構風格
  • 客戶端與服務端的
  • 基於組件模型的架構(EJB)
  • 分層架構(MVC)
  • 面向服務架構(SOA)
2.3 微服務的特色
  • 系統是由多個服務構成
  • 每一個服務能夠單獨獨立部署
  • 每一個服務之間是鬆耦合的,服務內部高內聚,服務外部低耦合,高內聚就是一個項目專一的完成一個功能
2.4 微服務的優勢與缺點

優勢:web

  • 容易測試
  • 可伸縮性強
  • 可靠性強
  • 跨語言程度更加靈活
  • 團隊協做容易
  • 系統迭代容易

缺點:spring

  • 運維成本太高,部署的數量較多
  • 接口兼容多版本
  • 分佈式系統的複雜性
  • 分佈式事務

2、MVC、RPC、SOA、微服務架構之間的區別

1.MVC架構

其實MVC就是傳統的單體架構shell

表明技術:SpringMVC、Spring、MyBatis等等。vim

2.RPC架構

RPC(Remote Procedure Call):遠程過程調用。他一種經過網絡從遠程計算機程序上請求 服務,而不須要了解底層網絡技術的協議。

表明技術:Thrift、Hessian 等等

3. SOA架構

SOA(Service oriented Architecture):面向服務架構

ESB(Enterparise Servce Bus):企業服務總線,服務中介。主要是提供了一個服務於服務之間的交互。 ESB 包含的功能如:負載均衡,流量控制,加密處理,服務的監控,異常處理,監控 告急等等。

表明技術:Mule、WSO2

4.微服務架構

微服務就是一個輕量級的服務治理方案。

表明技術:SpringCloud、dubbo 等等

3、微服務的設計原則

  • AKF拆分原則
  • 先後端分離原則
  • 無狀態服務
  • RestFul通訊風格

1. AKF拆分原則

業界對於可擴展的系統架構設計有一個樸素的理念,就是: **經過加機器就能夠解決容量和可用性問題。(若是一臺不行那就兩臺) **

這一理念在「雲計算」概念瘋狂流行的今天,獲得了普遍的承認!對於一個規模 迅速增加的系統而言,容量和性能問題固然是首當其衝的。可是隨着時間的向前, 系統規模的增加,除了面對性能與容量的問題外,還須要面對功能與模塊數量上 的增加帶來的系統複雜性問題以及業務的變化帶來的提供差別化服務問題。而許多系統,在架構設計時並未充分考慮到這些問題,致使系統的重構成爲常態,從 而影響業務交付能力,還浪費人力財力!對此,《可擴展的藝術》一書提出了一 個更加系統的可擴展模型—— AKF 可擴展立方 (Scalability Cube)。這個立方 體中沿着三個座標軸設置分別爲:X、Y、Z。

  • Y 軸(功能) —— 關注應用中功能劃分,基於不一樣的業務拆分
  • X 軸(水平擴展) —— 關注水平擴展,也就是」加機器解決問題」
  • Z 軸(數據分區) —— 關注服務和數據的優先級劃分,如按地域劃分
1.1 Y軸(功能 )

Y 軸擴展會將龐大的總體應用拆分爲多個服務。每一個服務實現一組相關的功 能,如訂單管理、客戶管理等。在工程上常見的方案是服務化架構(SOA) 。比 如對於一個電子商務平臺,咱們能夠拆分紅不一樣的服務,組成下面這樣的架構:

但經過觀察上圖容易發現,當服務數量增多時,服務調用關係變得複雜。爲系統添加一個新功能,要調用的服務數也變得不可控,由此引起了服務管理上的混亂。因此,通常狀況下,須要採用服務註冊的機制造成服務網關來進行服務治理。系統的架構將變成下圖所示:

1.2 X軸(水平擴展)

X 軸擴展與咱們前面樸素理念是一致的,經過絕對平等地複製服務與數據, 以解決容量和可用性的問題。其實就是將微服務運行多個實例,作集羣加負載均衡的模式。

爲了提高單個服務的可用性和容量, 對每個服務進行 X 軸擴展劃分。

1.3 Z軸(數據分區)

Z 軸擴展一般是指基於請求者或用戶獨特的需求,進行系統劃分,並使得劃分出來的子系統是相互隔離但又是完整的。以生產汽車的工廠來舉例:福特公司爲了發展在中國的業務,或者利用中國的廉價勞動力,在中國創建一個完整的子 工廠,與美國工廠同樣,負責完整的汽車生產。這就是一種Z軸擴展。

工程領域常見的 Z 軸擴展有如下兩種方案:

  • 單元化架構

    在分佈式服務設計領域,一個單元(Cell)就是知足某個分區全部業務操做 的自包含閉環。如上面咱們說到的Y軸擴展的 SOA 架構,客戶端對服務端節點 的選擇通常是隨機的,可是,若是在此加上Z軸擴展,那服務節點的選擇將再也不是隨機的了,而是每一個單元自成一體。以下圖:

  • 數據分區

    爲了性能數據安全上的考慮,咱們將一個完整的數據集按必定的維度劃分出 不一樣的子集。 一個分區(Shard),就是是總體數據集的一個子集。好比用尾號 來劃分用戶,那一樣尾號的那部分用戶就能夠認爲是一個分區。數據分區爲通常 包括如下幾種數據劃分的方式:

    1. 數據類型(如:業務類型)
    2. 數據範圍(如:時間段,用戶 ID)
    3. 數據熱度(如:用戶活躍度,商品熱度)
    4. 按讀寫分(如:商品描述,商品庫存)

2. 先後端分離原則

何爲先後端分離?先後端原本不就分離麼?這要從尷尬的 jsp 講起。分工精細化歷來都 是蛋糕作大的原則,多個領域工程師最好在不須要接觸其餘領域知識的狀況下合做,纔可能 使效率愈來愈高,維護也會變得簡單。jsp 的模板技術融合了 html 和 java 代碼,使得傳統 MVC 開發中的先後端在這裏如膠似漆,前端作好頁面,後端轉成模板,發現問題再找前端, 前端又看不懂 java 代碼......先後端分離的目的就是將這尷尬局面打破。 先後端分離原則,簡單來說就是前端和後端的代碼分離,咱們推薦的模式是最好採用物 理分離的方式部署,進一步促使更完全的分離。若是繼續直接使用服務端模板技術,如:jsp, 把 java、js、html、css 都堆到一個頁面裏,稍微複雜一點的頁面就沒法維護了。

這種分離方式有幾個好處:

  • 先後端技術分離,能夠由各自的專家來對各自的領域進行優化,這樣前段的用戶體 驗優化效果更好。
  • 分離模式下,先後端交互界面更清晰,就剩下了接口模型,後端的接口簡潔明瞭, 更容易維護。
  • 前端多渠道集成場景更容易實現,後端服務無需變動,採用統一的數據和模型,可 以支持多個前端:例如:微信 h5 前端、PC 前端、安卓前端、IOS 前端。

3. 無狀態服務

對於無狀態服務,首先說一下什麼是狀態:若是一個數據須要被多個服務共 享,才能完成一筆交易,那麼這個數據被稱爲狀態。進而依賴這個「狀態」數據的 服務被稱爲有狀態服務,反之稱爲無狀態服務。

那麼這個無狀態服務原則並非說在微服務架構裏就不容許存在狀態,表達 的真實意思是要把有狀態的業務服務改變爲無狀態的計算類服務,那麼狀態數據 也就相應的遷移到對應的「有狀態數據服務」中。

場景說明:例如咱們之前在本地內存中創建的數據緩存、Session 緩存,到 如今的微服務架構中就應該把這些數據遷移到分佈式緩存中存儲,讓業務服務變 成一個無狀態的計算節點。遷移後,就能夠作到按需動態伸縮,微服務應用在運 行時動態增刪節點,就再也不須要考慮緩存數據如何同步的問題。

4. RestFul的通信風格

做爲一個原則來說原本應該是個「無狀態通訊原則」,在這裏咱們直接推薦一 個實踐優選的 Restful 通訊風格 ,由於他有不少好處:

  • 無狀態協議 HTTP,具有先天優點,擴展能力很強。例如須要安全加密,有 現成的成熟方案 HTTPS 便可。
  • JSON 報文序列化,輕量簡單,人與機器都可讀,學習成本低,搜索引擎友好。
  • 語言無關,各大熱門語言都提供成熟的 Restful API 框架,相對其餘的一些 RPC 框架生態更完善。

4、SpringCloud簡介

1.什麼是SpringCloud

SpringCloud是一個服務治理平臺,提供了一些服務框架。包含了:服務註冊 與發現、配置中心、消息中心 、負載均衡、數據監控等等。

Spring Cloud 是一個微服務框架,**相比 Dubbo 等 RPC 框架, Spring Cloud 提 供的全套的分佈式系統解決方案。 **

Spring Cloud 對微服務基礎框架 Netflix 的多個開源組件進行了封裝,同時又實現 了和雲端平臺以及和 Spring Boot 開發框架的集成。

Spring Cloud 爲微服務架構開發涉及的配置管理,服務治理,熔斷機制,智能路由, 微代理,控制總線,一次性 token,全局一致性鎖,leader 選舉,分佈式 session,集 羣狀態管理等操做提供了一種簡單的開發方式。

Spring Cloud 爲開發者提供了快速構建分佈式系統的工具,開發者能夠快速的啓動 服務或構建應用、同時可以快速和雲平臺資源進行對接。

2. SpringCloud的項目的位置

SpingCloud是Spring 的一個頂級項目與 SpringBoot、SpringData 位於同一位置。

3.SpringCloud的子項目

3.1 SpringCloud Config

​ 配置管理工具,支持使用 Git 存儲配置內容,支持應 用配置的外部化存儲,支持客戶端配置信息刷新、加解密配置內容等

3.2 SpringCloud Bus

​ 事件、消息總線,用於在集羣(例如,配置變化事件)中 傳播狀態變化,可與 Spring Cloud Config 聯合實現熱部署。

3.3 Spring Cloud Netflix>

​ **針對多種 Netflix 組件提供的開發工具包,其中包括 Eureka、Hystrix、Zuul、Archaius 等。 **

  • Netflix Eureka

    一個基於 rest 服務的服務治理組件,包括服務註冊中心、服務註冊與服務發現機制的實現,實現了雲端負載均衡和中間層服務器的故障轉移。

  • Netflix Hystrix

    容錯管理工具,實現斷路器模式,經過控制服務的節點, 從而對延遲和故障提供更強大的容錯能力。

  • Netflix Ribbon

    客戶端負載均衡的服務調用組件。

  • Netflix Feign

    基於Ribbon和Hystrix的聲明式服務調用組件。

  • Netflix Zuul

    微服務網關,提供動態路由,訪問過濾等服務。

  • Netflix Archaius:

    配置管理 API,包含一系列配置管理 API,提供動 態類型化屬性、線程安全配置操做、輪詢框架、回調機制等功能。

3.4 Spring Cloud for Cloud Foundry

​ 經過 Oauth2 協議綁定服務到 CloudFoundry,CloudFoundry 是 VMware 推出的開源 PaaS 雲平臺。

3.5 Spring Cloud Sleuth

​ 日誌收集工具包,封裝了 Dapper,Zipkin 和 HTrace 操做。

3.6 Spring Cloud Data Flow

​ 大數據操做工具,經過命令行方式操做數據流。

3.7 Spring Cloud Security

​ 安全工具包,爲你的應用程序添加安全控制,主要是指OAuth2。

3.8 Spring Cloud Consul

​ 封裝了Consul操做,consul是一個服務發現與配置工具,與Docker容器能夠無縫集成。

3.9 Spring Cloud Zookeeper

​ 操做Zookeeper的工具包 , 用使用zookeeper方式的服務註冊和發現。

3.10 Spring Cloud Stream:

​ 數據流操做開發包,封裝了Redis、Rabbit、Kafka 等發送接收消息。

3.11 Spring Cloud CLI

​ 基於 Spring Boot CLI,可讓你以命令行方式快速創建雲組件。

5、SpringCloud與Dubbo的區別

6、 Spring Cloud版本說明

1.常見版本號說明

​ 軟件版本號:2.0.2.RELEASE

  • 2:主版本號。當功能模塊有較大更新或者總體架構發生變化時,主版本號會更新

  • 0:次版本號。次版本表示只是局部的一些變更。

  • 2:修改版本號。通常是 bug 的修復或者是小的變更

  • RELEASE:希臘字母版本號。次版本號用戶標註當前版本的軟件處於哪一個開發階段

1.1希臘字母版本號
  • Base:設計階段。只有相應的設計沒有具體的功能實現
  • Alpha:軟件的初級版本。存在較多的 bug
  • Bate:表示相對 alpha 有了很大的進步,消除了嚴重的 bug,還存在一些潛在的 bug。
  • Release:該版本表示最終版。

2. Spring Cloud 版本號說明

2.1爲何 Spring Cloud 版本用的是單詞而不是數字?

設計的目的是爲了更好的管理每一個 Spring Cloud 的子項目的清單。避免子的版本號與子 項目的版本號混淆。

2.2 版本號單詞的定義規則

採用倫敦的地鐵站名稱來做爲版本號的命名,根據首字母排序,字母順序靠後的版本號越大。

2.3 版本發佈計劃說明

7、RabbitMQ

1.什麼是RabbitMQ

MQ全稱Message Queue(消息隊列),是一種應用程序與應用程序之間通訊的一種方式,應用程序能夠經過向消息隊列中讀寫消息進行信息的交互,而不是以應用相互調用的方式進行通訊。

2.安裝RabbitMQ

2.1 安裝rabbitmq所須要的依賴包
yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz
複製代碼
2.2 下載安裝包(cd /usr/local/software)
wget www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-5.el7.lux.x86_64.rpm
wget www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm
複製代碼

2.3 安裝服務命令
#第一步:安裝erlang語言環境
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm
#第二步:安裝socat加解密軟件
rpm -ivh socat-1.7.3.2-5.el7.lux.x86_64.rpm
#第三步:最後安裝rabbitmq
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm
複製代碼
2.4 修改集羣用戶與鏈接心跳檢測

**注意修改vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app文件 **

修改:loopback_users 中的 <<"guest">>,只保留guest(不修改只能經過localhost訪問)

2.5 修改本機系統文件
#修改 
vim /etc/rabbitmq/rabbitmq-env.conf
複製代碼

添加:NODENAME=rabbit

#修改
vim /etc/hostname
複製代碼

#修改本地文件 
vim /etc/hosts
複製代碼

#驗證服務器是可用的
rabbitmq-server start &
複製代碼

**執行管控臺插件 **

rabbitmq-plugins enable rabbitmq_management
複製代碼

#檢查端口
lsof -i:5672
複製代碼

#經過
ps -ef|grep rabbitmq
複製代碼

訪問地址:http://192.168.159.8:15672

#下載延時插件:
wget https://dl.bintray.com/rabbitmq/communityplugins/3.6.x/rabbitmq_delayed_message_exchange/rabbitmq_delayed_message_exchange-20171215- 3.6.x.zip  
複製代碼
#解壓延時插件
unzip rabbitmq_delayed_message_exchange-20171215-3.6.x.zip
複製代碼
#把延時插件拷貝到指定目錄下
cp rabbitmq_delayed_message_exchange-20171215-3.6.x.ez /usr/lib/rabbitmq/lib/rabbitmq_server-3.7.5/plugins
複製代碼
#啓動延時插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
複製代碼

3.命令行和管控臺

**開啓管控臺插件 rabbitmq-plugus rabbitmq_management 來開啓管控臺 **

測試鏈接: http://ip:15672(來訪問) 用戶名密碼 guest/guest

3.1 管理控制檯命令

a.起停服務命令

#啓動服務
rabbitmqctl start_app
複製代碼

啓動rabbitmq節點保證須要erlang虛擬機節點起來才能執行)

#中止服務
rabbitmqctl stop_app
複製代碼

中止rabbtimq節點,可是不會中止erlang節點rabbitmqctl stop都會中止

#查看服務狀態 
rabbtimqctl status
複製代碼

b. 用戶操做命令

#查看全部用戶列表
rabbitmqctl list_users
複製代碼
#添加用戶
rabbitmqctl add_user luyi luyi
複製代碼
#設置rabbitmq用戶的角色
rabbitmqctl set_user_tags luyi administrator
複製代碼
#爲用戶設置權限
rabbitmqctl set_permissions -p / luyi ".*" ".*" ".*"

rabbitmqctl set_permissions -p <虛擬機> <用戶名> ".*" ".*" ".*"
複製代碼
#列出用戶權限
rabbitmqctl list_user_permissions luyi
複製代碼
#清除用戶權限
rabbitmqctl clear_permissions -p <虛擬機> <用戶名>
rabbitmqctl clear_permissions -p / root
複製代碼
#刪除用戶
rabbitmqctl delete_user root #root是用戶名
複製代碼
#修改密碼
rabbitmqctl change_password 用戶名 新密碼
複製代碼

c.虛擬主機操做

rabbitmqctl add_vhost /cloudmall 增長一個虛擬主機

rabbitmqctl list_vhosts; 查看全部的虛擬主機

rabbitmqctl list_permissions -p /cloudmall 查看虛擬主機的權限

rabbitmqctl delete_vhost /cloudmall 刪除虛擬主機

d. 操做隊列命令

rabbitmqctl list_queues 查詢全部隊列

rabbitmqctl -p vhostpath purge_queue blue 清除隊列消息

e. 高級命令

rabbitmqctl reset 移除全部數據 該命令須要在 rabbitmqctl stop_app命令以後才執行(也就是說 在服 務中止後) r

abbitmqctl join_cluster [--ram] 組成集羣命令

rabbitmqctl cluster_status 查看集羣狀態

rabbitmqctl change_cluster_node_type dist|ram 修改集羣節點存儲數據模式

rabbitmqctl forget_cluster_node [--offline]忘記節點 (摘除節點)

rabbitmqctc rename_cluster_node oldnode1 newnode1 oldnode2 newnode2 修改節點名稱

4.爲何使用RabbitMQ

4.1 實現異步

4.2 解耦

4.3 流量削峯

5.消息隊列基礎知識

5.1 Provider

消息生產者,也就是發送消息的程序

5.2 Consumer

消息消費者,也就是接收消息的程序

5.3 沒有使用消息隊列的通訊方式

5.4 使用消息隊列後的通訊方式

5.5 什麼是隊列

隊列就像生活中的商店,商品製造商是消息生產者,顧客是消息消費者,他們之間經過商店實現交互

5.6 隊列和應用程序的關係

多個消息生產者能夠將消息發送到同一個消息隊列中,多個消息消費者能夠從同一個消息隊列中取出消息。

6.RabbitMQ入門

6.1 建立項目
6.2 添加依賴
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
複製代碼
6.3 配置全局配置文件
#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi
複製代碼
6.4 建立配置類
/** * Author: LuYi * Date: 2019/11/3 14:03 * Description: 隊列配置類 */
@Configuration
public class QueueConfig {

    /** * 建立隊列 * @return */
    @Bean
    public Queue createQueue(){
        return new Queue("hello-queue");
    }
}
複製代碼
6.5 編寫消息發送者
/** * Author: LuYi * Date: 2019/11/3 14:06 * Description: 消息發送者 */
@Component
public class Sender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /** * 發送消息的方法 */
    public void send(String msg){
        //向消息隊列發送消息
        //參數一: 隊列名稱
        //參數二: 消息
        rabbitTemplate.convertAndSend("hello-queue", msg);
    }
}
複製代碼
6.6 編寫消息接收者
/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 */
@Component
public class Receiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitListener(queues = "hello-queue")
    public void process(String msg){

        System.out.println("Receiver : " + msg);
    }
}
複製代碼
6.7 測試
/** * 消息隊列測試類 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Springcloud01MqApplication.class)
class Springcloud01MqApplicationTests {

	@Autowired
	private Sender sender;

	@Test
	void contextLoads() {
	}

	/** * 測試消息隊列 */
	@Test
	public void test1(){
		sender.send("Hello RabbitMQ");
	}
}
複製代碼

7.RabbitMQ原理圖

1.Message(消息):消息是不具名的,它是由消息頭和消息體組成。消息體是不透明的,而消息頭則由一系列可選屬性組成,這些屬性包括:routing-key(路由鍵)、priority(相對於其餘消息的優先權)、delivery-mode(指出消息可能持久性存儲)等。

2.Publisher(生產者):向交換機發送消息的客戶端程序

3.Consumer(消費者):從消息隊列中獲取消息的客戶端程序

4.Exchange(交換機):用來接收客戶端發過來的消息,並將這些消息路由給服務器中的消息隊列

​ 三種經常使用的交換機:

​ a.direct(發佈與訂閱,徹底匹配)

​ b.fanout(廣播)

​ c.topic(主題,規則匹配)

5.Binding(綁定):用於交換機與消息隊列之間的關聯,一個綁定就是根據路由鍵將交換機與消息隊列鏈接起來的規則。

6.Queue(消息隊列):用於保存消息,直到將消息發送給消費者

7.Routing-key(路由鍵):RabbitMQ決定將消息投遞到那個消息隊列的規則。隊列經過路由鍵綁定交換機,消息發送到MQ服務器時,消息將擁有一個路由鍵,即使是空的,RabbitMQ也會將其和綁定使用的路由鍵進行匹配。

​ 若是匹配,消息會被髮送到消息隊列,若是不匹配,消息將進入黑洞。

8.Connection(連接):Rabbit服務器和服務之間創建的TCP鏈接

9.Channel(信道):信道是TCP中的虛擬連接,好比電纜就是TCP,信道則是一個獨立光纖束。一條TCP鏈接創建多條信道是沒有問題的。

​ TCP一旦打開,就會建立AMQP信道。不管是發佈消息、接收消息、訂閱隊列,這些動做都是經過信道完成的

10.Virtual Host(虛擬主機):表示一臺交換機和消息隊列。虛擬主機是共享相同的身份認證和加密環境的獨立服務器域 每一個 vhost 本質上就是一個 mini 版的 RabbitMQ 服務器,擁有本身的隊列、交換器、綁定和權限機制。 vhost 是 AMQP 概念的基礎,必須在連接時指定, RabbitMQ 默認的 vhost 是/  

11.Borker:表示消息隊列的服務器實體

交換機和路由器的關係是什麼?

交換機須要經過路由鍵和消息隊列進行綁定,若是路由鍵相同,那麼消息會被路由到對應的消息隊列中,能夠理解爲路由鍵是決定消息發送到那個消息隊列的規則

8、RabbitMQ交換器

1.Direct(發佈與訂閱 徹底匹配)

1.1 需求

1.2 建立項目

rabbitmq-direct-consumer

rabbitmq-direct-provider

1.3 修改全局配置文件

consumer的配置文件

#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi

#設置交換器的名稱(處理日誌的交換器)
mq.config.exchange=log.direct

#info級別的隊列名稱
mq.config.queue.info=log.info

#info的路由鍵
mq.config.queue.info.routing.key=log.info.routing.key

#error級別的隊列名稱
mq.config.queue.error=log.error

#error的路由鍵
mq.config.queue.error.routing.key=log.error.routing.key
複製代碼

provider的配置文件

#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi

#設置交換器的名稱(處理日誌的交換器)
mq.config.exchange=log.direct

#info的路由鍵
mq.config.queue.info.routing.key=log.info.routing.key

#error的路由鍵
mq.config.queue.error.routing.key=log.error.routing.key
複製代碼
1.4 編寫consumer

InfoReceiver

/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.info}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.DIRECT),
                key = "${mq.config.queue.info.routing.key}"
        )
)
public class InfoReceiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitHandler
    public void process(String msg){

        System.out.println("InfoReceiver : " + msg);
    }
}
複製代碼

ErrorReceiver

/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.error}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.DIRECT),
                key = "${mq.config.queue.error.routing.key}"
        )
)
public class ErrorReceiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitHandler
    public void process(String msg){

        System.out.println("ErrorReceiver : " + msg);
    }
}
複製代碼
1.5 編寫provider
/** * Author: LuYi * Date: 2019/11/3 14:06 * Description: 消息發送者 */
@Component
public class Sender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //交換器名稱
    @Value("${mq.config.exchange}")
    private String exchange;

    //路由鍵名稱
    @Value("${mq.config.queue.error.routing.key}")
    private String routingKey;

    /** * 發送消息的方法 */
    public void send(String msg){
        //向消息隊列發送消息
        //參數一: 交換器名稱
        //參數二: 路由鍵
        //參數三: 消息
        rabbitTemplate.convertAndSend(exchange, routingKey, msg);
    }
}
複製代碼
1.6 測試
/** * 消息隊列測試類 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Springcloud01MqApplication.class)
class Springcloud01MqApplicationTests {

	@Autowired
	private Sender sender;

	@Test
	void contextLoads() {
	}

	@Test
	public void test1() throws InterruptedException {
		while (true){
			Thread.sleep(1000);
			sender.send("Hello RabbitMQ");
		}
	}

}

複製代碼

2.Topic交換器(主題,規則匹配)

2.1 需求

2.2 建立項目

rabbitmq-topic-consumer

rabbitmq-topic-provider

2.3 修改配置文件

provider

#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi

#設置交換器的名稱(處理日誌的交換器)
mq.config.exchange=log.topic
複製代碼

consumer

#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi

#設置交換器的名稱(處理日誌的交換器)
mq.config.exchange=log.topic

#info級別的隊列名稱
mq.config.queue.info=log.info

#error級別的隊列名稱
mq.config.queue.error=log.error

#log級別的隊列名稱
mq.config.queue.all=log.all
複製代碼
2.4 編寫provider

UserSender

/** * Author: LuYi * Date: 2019/11/3 14:06 * Description: 消息發送者 */
@Component
public class UserSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //交換器名稱
    @Value("${mq.config.exchange}")
    private String exchange;

    /** * 發送消息的方法 */
    public void send(String msg){
        //向消息隊列發送消息
        //參數一: 交換器名稱
        //參數二: 路由鍵
        //參數三: 消息
        rabbitTemplate.convertAndSend(exchange, "user.log.debug", "user.log.debug "+msg);
        rabbitTemplate.convertAndSend(exchange, "user.log.info", "user.log.info "+msg);
        rabbitTemplate.convertAndSend(exchange, "user.log.warn", "user.log.warn "+msg);
        rabbitTemplate.convertAndSend(exchange, "user.log.error", "user.log.error "+msg);
    }
}
複製代碼

ProductSender

/** * Author: LuYi * Date: 2019/11/3 14:06 * Description: 消息發送者 */
@Component
public class ProductSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //交換器名稱
    @Value("${mq.config.exchange}")
    private String exchange;

    /** * 發送消息的方法 */
    public void send(String msg){
        //向消息隊列發送消息
        //參數一: 交換器名稱
        //參數二: 路由鍵
        //參數三: 消息
        rabbitTemplate.convertAndSend(exchange, "product.log.debug", "product.log.debug "+msg);
        rabbitTemplate.convertAndSend(exchange, "product.log.info", "product.log.info "+msg);
        rabbitTemplate.convertAndSend(exchange, "product.log.warn", "product.log.warn "+msg);
        rabbitTemplate.convertAndSend(exchange, "product.log.error", "product.log.error "+msg);
    }
}

複製代碼

OrderSender

/** * Author: LuYi * Date: 2019/11/3 14:06 * Description: 消息發送者 */
@Component
public class OrderSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //交換器名稱
    @Value("${mq.config.exchange}")
    private String exchange;

    /** * 發送消息的方法 */
    public void send(String msg){
        //向消息隊列發送消息
        //參數一: 交換器名稱
        //參數二: 路由鍵
        //參數三: 消息
        rabbitTemplate.convertAndSend(exchange, "order.log.debug", "order.log.debug "+msg);
        rabbitTemplate.convertAndSend(exchange, "order.log.info", "order.log.info "+msg);
        rabbitTemplate.convertAndSend(exchange, "order.log.warn", "order.log.warn "+msg);
        rabbitTemplate.convertAndSend(exchange, "order.log.error", "order.log.error "+msg);
    }
}
複製代碼
2.5 編寫consumer

InfoReceiver

/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.info}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.TOPIC),
                key = "*.log.info"
        )
)
public class InfoReceiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitHandler
    public void process(String msg){

        System.out.println("InfoReceiver : " + msg);
    }
}
複製代碼

ErrorReceiver

/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.error}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.TOPIC),
                key = "*.log.error"
        )
)
public class ErrorReceiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitHandler
    public void process(String msg){

        System.out.println("ErrorReceiver : " + msg);
    }
}
複製代碼

AllReceiver

/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.all}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.TOPIC),
                key = "*.log.*"
        )
)
public class AllReceiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitHandler
    public void process(String msg){

        System.out.println("AllReceiver : " + msg);
    }
}
複製代碼
2.6 測試
/** * 消息隊列測試類 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Springcloud01MqApplication.class)
class Springcloud01MqApplicationTests {

	@Autowired
	private UserSender userSender;
	@Autowired
	private ProductSender productSender;
	@Autowired
	private OrderSender orderSender;

	@Test
	void contextLoads() {
	}

	@Test
	public void test1() {
		userSender.send("UserSender...");
		productSender.send("ProductSender...");
		orderSender.send("OrderSender...");
	}

}
複製代碼

3. Fanout交換器(廣播)

3.1 需求

3.2 建立項目

rabbitmq-fanout-consumer

rabbitmq-fanout-provider

3.3 修改配置文件

consumer

#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi

#設置交換器的名稱
mq.config.exchange=order.fanout

#短信隊列名稱
mq.config.queue.sms=order.sms

#push隊列名稱
mq.config.queue.push=order.push
複製代碼

provider

#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi

#設置交換器的名稱(處理日誌的交換器)
mq.config.exchange=order.fanout
複製代碼
3.4 編寫consumer

SmsReceiver

/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.sms}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.FANOUT)
        )
)
public class SmsReceiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitHandler
    public void process(String msg){

        System.out.println("SmsReceiver : " + msg);
    }
}
複製代碼

PushReceiver

/** * Author: LuYi * Date: 2019/11/3 14:12 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.push}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.FANOUT)
        )
)
public class PushReceiver {

    /** * 接收消息的方法,採用消息隊列監聽機制 * @param msg */
    @RabbitHandler
    public void process(String msg){

        System.out.println("PushReceiver : " + msg);
    }
}
複製代碼
3.5 編寫provider
/** * Author: LuYi * Date: 2019/11/3 14:06 * Description: 消息發送者 */
@Component
public class OrderSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //交換器名稱
    @Value("${mq.config.exchange}")
    private String exchange;

    /** * 發送消息的方法 */
    public void send(String msg){
        //向消息隊列發送消息
        //參數一: 交換器名稱
        //參數二: 路由鍵
        //參數三: 消息
        rabbitTemplate.convertAndSend(exchange, "", msg);
    }
}
複製代碼
3.6 測試
/** * 消息隊列測試類 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Springcloud01MqApplication.class)
class Springcloud01MqApplicationTests {

	@Autowired
	private OrderSender orderSender;

	@Test
	void contextLoads() {
	}

	@Test
	public void test1() throws InterruptedException {
		while (true){
			Thread.sleep(1000);
			orderSender.send("Hello RabbitMQ");
		}
	}

}
複製代碼

4.使用RabbbitMQ實現鬆耦合設計

4.1 修改配置文件
#設置應用的名稱
spring.application.name=springcloud01-mq

#指定rabbitmq
spring.rabbitmq.host=192.168.234.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=luyi
spring.rabbitmq.password=luyi

#設置交換器的名稱
mq.config.exchange=order.fanout

#短信隊列名稱
mq.config.queue.sms=order.sms

#push隊列名稱
mq.config.queue.push=order.push

#紅包服務隊列名稱
mq.config.queue.red=order.red
複製代碼
4.2 添加receiver

RedReceiver

/** * Author: LuYi * Date: 2019/11/4 16:20 * Description: 消息接收者 * * @RabbitListener bindings:綁定隊列 * * @QueueBinding value:綁定隊列名稱 * exchange:配置交換器 * * @Queue value:配置隊列名稱 * autoDelete:是否爲可刪除的臨時隊列 * * @Exchange value:爲交換器起名 * type:指定當前交換器的類型 */
@Component
@RabbitListener(
        bindings = @QueueBinding(
                value = @Queue(value = "${mq.config.queue.red}", autoDelete = "true"),
                exchange = @Exchange(value = "${mq.config.exchange}", type = ExchangeTypes.FANOUT)
        )
)
public class RedReceiver {

    @RabbitHandler
    public void process(String msg){
        System.out.println("給用戶發送10元紅包 " + msg);
    }
}
複製代碼

9、RabbitMQ消息處理

1. RabbitMQ的消息持久化處理

1.1 建立項目

rabbitmq-direct-durable-provider

rabbitmq-direct-durable-consumer

1.2 autoDelete

@Queue:當全部消費客戶端鏈接斷開後,是否自動刪除隊列,若是設置成true表示刪除,false表示不刪除

@Exchange:當全部綁定隊列都不在使用時,是否自動刪除交換機,true:刪除,false:不刪除

2.RabbitMQ中的消息確認ACK機制

  • 什麼是消息確認ACK

    若是在消費者接收消息是,服務器出現了異常致使這條消息沒法被接收,這是RabbitMQ能夠經過ACK機制保證消息不丟失

  • ACK的消息確認機制

    ACK機制是消費者接收到消息以後向RabbitMQ發送的,RabbitMQ收到ACK後纔會將該消息從消息隊列中刪除

    • 若是RabbitMQ沒有接收到消費者的ACK標識,那麼RabbitMQ會將這個消息放入消息隊列中再次發送。
    • 若是在集羣狀況下,RabbitMQ會將這個消息推送給在線的其餘消費者。這種機制確保了消費者服務端在發生故障時不會丟失任何消息。
    • 消息永遠不會從RabbitMQ中刪除,只有當消費者正確發送了ACK而且RabbitMQ也作出了確認以後纔會進行刪除。
    • 消息的ACK確認機制是默認打開的。
  • ACK機制的開發注意事項

    若是忘記了ACK,那麼當Consumer退出時,Message會一直重發,這樣就會佔用大量的RabbitMQ的內存,因爲RabbitMQ會長時間運行,因此這個狀況是致命的。

相關文章
相關標籤/搜索