消息中間件:RocketMQ 介紹(特性、術語、原理、優缺點、消息順序、消息重復)

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。

消息中間件的作用

1. 應用解耦

2. 異步處理

比如用戶注冊場景,注冊主流程完成以后,需要調用郵件系統發送郵件通知用戶注冊成功,可能還需要調用其他系統。這是串行的,如果一個系統依賴很多系統,那么這個主流程會比較長,耦合度高,整個系統維護成本也會越來越高。那么我們就可以使用消息中間件來進行解耦,通過發布訂閱模式,完成用戶注冊之后,向中間件發送消息,這樣就可以馬上給用戶返回,至于后續工作其他系統向中間件訂閱這個消息并完成后續工作就好。這也就是一個解耦和異步處理過程。

?

中間件有下面兩種模型

點對點模型

1.png

發布訂閱模型

2.png

?

消息中間件的解耦和異步是兩個最重要的需求點,除此之外還應該做一些其他事情比如:

  • 保證一致性,產生消息和發送消息是一致的,也就是如果操作成功,那么消息一定發送成功;如果業務操作沒有成功那么就不能發送消息

  • 具備一定消息堆積能力,可以為后端擋住一些數據流保證后端不會被壓垮

  • 具備消息實時性,保證消息的低延遲

  • 具備消息的可靠性,主要是可靠地存儲和投遞

?

消息系統里面應該有這樣一個假設:消息一定會堆積。下游系統通常有很多,里面有重要的也不重要的,面對突發流量高峰,一定會有后端系統處理不過來的情況,從而造成消息堆積;當然還有一種情況是后端系統出現問題導致暫時無法消費消息從而造成消息中間件的消息堆積。所以中間件要起到蓄水池的作用。

?

數據一致性,這個很容易理解,因為是分布式異步的,但是又不能容忍數據出錯,所以在性能和數據一致性方面就需要有所妥協,通常在互聯網行業中采取最終一致性。需要注意的是最終一致性和弱一致性不同,弱一致性表示允許在異常情況下數據可能不一致,而最終一致性則是在某段時間內允許不一致但是最終會一致。

?

RocketMQ介紹

基于發布訂閱的隊列模型消息中間件,它只有發布和訂閱的消息方式,消息類型只支持Message,消息可以持久化。服務端使用JAVA編寫,客戶端支持JAVA、C++。阿里2012年開源,之后作為Apache基金會的一個項目進行維護。是一款低延遲、高可靠、可伸縮、易于使用的中間件。在Github上有相關介紹。

?

特性

消息可靠性:

  • 生產者的可靠性保證:生產者發送消息后返回SendResult,如果isSuccess返回true,則表示消息已經確認發送到服務器并被服務器接收保存。整個發送過程是一個同步過程。

  • 服務器的可靠性:消息生產者發送的消息,RocketMQ服務收到后在做必要的校驗和檢查之后馬上保存到磁盤,寫入成功后返回給生產者。因此可以確認每條發送結果為成功的消息都會被消息服務器寫入磁盤。

  • 消費者的可靠性:消費者是一條一條順序消費的,之后在成功消費一條后才會消費嚇一跳。如果在消費某一條消息時失敗則會重試消費這條消息,默認為5次,如果超過最大次數仍然無法消費,則將消息保存到本地,后臺線程繼續重試消費,主線程則會繼續往后走,消費隊列后面的消息。

    ?

消息持久性RocketMQ收到消息后,會將消息持久化到文件,并利用Linux文件系統內存來提高性能

消息實時性:RocketMQ采取長輪詢+PULL模式保證消息的持久性

消息重復:對于消費者來說,通過拉取方式將消息保存到本地,消費完再向服務器返回,在網絡異常的情況下可能會出現重復。

消息過濾:

  • 服務器端過濾:減少不必要消息傳輸,但是會增加服務器負擔

  • 客戶端過濾:根據客戶端需求來定制消息,缺點是客戶端會收到對它來說沒用的消息,如果客戶端無法承載這么多消息就會導致故障

消息堆積:支持10億級別的消息堆積,不會因為消息堆積影響性能

?

術語說明

?

角色說明
Producer

Producer:

生產者,用于將消息發送到RocketMQ,生產者本身既可以是生成消息,也可以對外提供接口,由外部來調用接口,再由生產者將受到的消息發送給MQ。

Consumer

Consumer:

消費者,從Broker拉取消息進行消費。從應用角度來說有兩類消費者:

  • PullConsumer:主動拉取消息,一旦拉取到消息,應用的消費進程進行初始化

  • PushConsumer:封裝消息拉取,消費進程和內部

Broker

Broker:

RocketMQ服務器,也是整個服務的核心,它實現了消息的存儲、拉取功能。它通常以集群方式啟動,并可配置主從,每個broker上提供對指定topic的服務。理解了broker的原理以及它和其他服務交互的過程,也就命令消息中間件的原理,其實都大同小異。它具有2中角色

  • Master:能寫、能讀

  • Slave:只能讀,不能寫

Topic

Topic:

消息的主題,由用于定義并在服務端配置,消費者可以按照主題進行訂閱,也就是消息分類,通常一個應用一個Topic

Message

Message:

在生產者、消費者、服務器之間傳遞的消息,一個message必須屬于一個Topic

Namesrv

Namesrv:

一個無狀態的名稱服務,可以集群部署,每一個broker啟動的時候都會向名稱服務器注冊,主要是接收broker的注冊(broker每十秒就會向所有名稱服務器發送心跳請求,同時注冊topic信息到名稱服務器),接收客戶端的路由請求并返回路由信息,你可以理解為服務自動發現,就是相當于zookeeper在dubbo框架中的作用。

  • 生產者發消息時會根據Topic向名稱服務器獲取到指定broker的路由信息

  • 消費者根據Topic到名稱服務器獲取該Topic到broker的路由信息

Group

Group:

組名,一類消費者或者生產者的集合名稱。

  • 消費者組,消費相同Topic內容的消費者,可以并行消費Topic中Partition中的消息。

  • 生產者組,生產相同Topic內容的生產者

Offset

Offset:

偏移量,消費者拉取消息時需要知道上一次消費到了什么位置,這一次從哪里開始。

Partition

Partition:

分區,Topic物理上的分組,一個Topic可以分為多個分區,每個分區是一個有序的隊列。分區中的每條消息都會給分配一個有序的ID,也就是偏移量。

分區的目的:

  • 減緩日志文件占用磁盤空間,消息需要持久化到文件,分區可以將消息粒度細分,每個分區可以存放在不同的磁盤空間中

  • 不同消費者同時消費分區中的數據,一個分區僅由一個消費者組中的消費者消費,1個消費者可以同時消費多個分區。

  • 可以實現負載均衡,如果同一個Topic的消息都放在同一個Broker上,那消費的時候同一個Topic的消費者都去同一個Broker上消費,這樣會帶來壓力,如果通過分區放在不同Broker上,這樣就可以到不同的Broker上消費,當然同一個ID的消息只能存在一個分區上。你可以想象A這個topic的消息有10個那么每個消息有1個ID,如果分布10個消息分布在不同的分區上,比如3個,那就形成3-3-4,消費者去消費的時候消費10條消息時通過3個分區完成這樣就提高了吞吐量。

Topic是消息的邏輯隊列,分區是物理隊列。可以通過配置文件來設置topic的默認分區數量,也可以在新建立topic的時候指定。建議分區數量和消費者數量一致,因為消費者數量多,多出來的不會去消費消息的,因為一個隊列只能被一個消費者消費。如果消費者數量少則消費者就會比較繁忙。

Tag

Tag:

用于對消息進行過濾,理解文件message的子主題,同一業務不同目的的message可以用相同的topic但是可以用不同的tag來區分,在隊列中tag在消息的數據結構中被 轉換為一個8byte的hashcode,這樣節省空間。過濾分兩步:

  1. 在Broker端進行Message Tag對比,先遍歷Consume Queue,如果存儲的Message tag與訂閱的tag不符合就跳過,符合則傳輸給Consumer,在隊列中繼續比對hashcode

  2. Consumer收到消息后,對比真實的Message Tag字符串,而不是Hashcode,這樣避免HASH沖突。

key

key:

消息的KEY字段是為了唯一表示消息的,方便查問題,不是說必須設置,只是說設置為了方便開發和運維定位問題,這個KEY可以是訂單ID等。

?

原理

消費者:

  • Push Consumer,應用向Consumer對象注冊一個Listener接口,一但收到消息,Consumer對象立刻回調Listener接口方法

  • Pull Consumer,應用主動調用Consumer的拉取消息方法,從Broker拉消息

消費模式:

  • 廣播模式:一條消息被多個消費者消費,即使它們屬于同一個消費者組,消息會被組中的每個成員消費一次。

  • 集群模式:消息會被平均分配到消費者組中進行消費。

消息模式:

  • 順序消息:消息的消費順序要和發送的順序一致,一類消息為滿足順序性,生產者必須單線程順序發送且發送到同一個隊列,這樣消費者就可以按照生產者發送的順序去消費。

  • 普通順序消息:正常情況下可以保證完全順序消費,但是一旦發生異常,比如broker重啟,由于隊列總數發生變化,會產生短暫的消息順序不一致。如果業務可以容忍這種異常情況則可以使用。

  • 嚴格順序消息:無論任何情況下都必須保證消息的順序,但是這就犧牲分布式的高可用功能,也就是Broker集群中只要有一臺不可用,那么整個集群就不可用。如果集群部署模式為同步雙寫模式,那么可以通過備機自動切換來避免,不過仍然存在短暫間隙的服務不可用。

消息的存儲

1.png

生產者上產消息,根據Topic選擇其對應的某一個分區,然后發送到這個分區所在的Brocker上,消費者根據訂閱的Topic選擇去Topic的某一個分區拉取消息。

RocketMQ收到消息后會把消息保存在本地文件中,每個文件最大上線1G,如果寫入消息時超過當前文件大小,會建立一個新文件,文件名為起始字節大小。消息寫入是順序的,讀取是隨機的,因為數據持久化當前寫入文件只有一個,所以可以是順序寫入,但是讀取的時候因為有多個邏輯隊列,每個邏輯隊列由多個分區所以就出現多個邏輯讀隊列,這樣讀取的時候就是隨機的。如何提高讀取性能呢?就盡可能讓讀命中系統pageCache,減少磁盤IO次數。RcoketMQ的持久化是先寫入pageCache頁面高速緩存,然后刷盤,這樣保證內存與磁盤都有一份相同的數據,訪問時直接從內存讀取。另外一方面RocketMQ在文件讀寫方面做了優化,采用內存映射方式完成,也就是把磁盤文件映射到內存地址空間,避免了內核空間到用戶空間的復制。

支持的部署架構

?

集群方式消息可靠性(Master宕機)服務可用性特點其他說明
一組主主同步刷盤消息一條都不會丟失整體可用,未被消費的消息無法取得,影響實時性結構簡單、擴容方便、性能最高適合消息可靠性高,實時性低的需求
一組主從異步有毫秒級丟失,同步雙寫不丟失主備不能切換,且備機只能讀不能寫,會造成服務整體不可用?不推薦使用

多組主從

(異步復制)

故障是會丟失消息整體可用,實時性影響是毫秒級別,該組服務只能讀不能寫結構復雜、擴容方便,性能很高。適合消息可靠性中等,實時性要求中等的場景
多組主從(同步雙寫)不丟消息整體可用,不影響實時性。該組服務只能讀不能寫。不能自動切換。結構復雜,擴容方便,性能比異步低一點,所以實時性也并不比異步方式高太多。適合消息可靠性高,實時性中等,性能要求不高的場景。

推薦的架構如下:

Snip20180204_10.png

高要求則使用多組主從同步雙寫,低要求使用主主方案。

應用場景

  • RocketMQ應用到Cache,可以用在大量機器同步信息的場景

  • 業務削峰,在大量交易涌入時,后端可能無法及時處理,所以MQ的大量消息堆積功能就可以發揮作用。

  • 日志收集,RocketMQ的設計模型從Kafka衍生而來,kafka在日志收集系統中充當緩沖功能,隨意RocketMQ也適用此場景

  • 對可靠性要求很高的場景,尤其是電商里面的訂單扣款,因為扣款要涉及到很多第三方支付。

優缺點

優點

  • 順序性,它支持順序性,可以做到局部有序,在單線程內使用該生產者發送的消息按照發送的順序到達服務器并存儲,并按照相同順序被消費,但前提是這些消息發往同一服務器的同一個分區

  • 實時性:采取長輪詢+PULL消費消息,你可以自己決定如何在響應性和吞吐量之間做平衡,配合合理的參數設置來獲得更高的響應時間,實時性不低于PUSH方式

  • 提供了豐富的拉取模式

  • 支持10億級別的消息堆積,不會因為堆積導致性能下降

  • 高效的訂閱者水平擴展機制

缺點

  • 消息重復問題,它不能保證不重復,只能保證正常情況下不重復

  • 不支持分布式事務

  • 消息過濾功能擴展比較單一

?

消息順序

消息順序是只可以按照消息發送的順序進行消費。一個訂單產生3條消息,訂單創建、付款、訂單完成。消費時只有按照順序消費才有意義,不可能先消費付款消息再消費訂單創建消息,這樣就亂了。另外,多筆訂單又可以并行消費。如何保證呢?

一個訂單產生的消息只能發送給同一個MQ服務器中的同一個分區,并且按順序發送,這樣才能在理論上保證消費者消費時是按照順序消費的,因為一個分區就是一個邏輯隊列。生產者雖然按順序發送,但是第一條消息到達MQ的耗時比第二條多,那么第二條則會被先消費,這樣就又導致消費時不是順序的。那么如何解決呢?可以采取只有第一條被消費者消費成功后再發送第二條。看下圖:

1.png

但是如果第一條被發送到消費者后,消費者沒有響應(消費者發送響應但是因為網絡問題丟失或者消費者就沒有收到消息),那么在這種情況下你是繼續發送第二條還是重發第一條呢?如果是嚴格消息順序,那肯定是重發第一條,但是如果是消費者消費后的響應丟失了,那么重發第一條就會造成重復消費。

?

從另外一方面看,如果不考慮網絡異常,那么要實現嚴格消息,就必須采取一種一對一關系,生產者A的消息對應到MQ服務器1的X隊列,消費者A消費X隊列。這樣串行結構就會造成系統吞吐量太低;更多異常需要處理比如消費端出現問題,那么整個消息隊列就會出現阻塞。RocketMQ通過輪詢所有隊列來確定消息發送到哪一個隊列(負載均衡),比如相同訂單號的消息會被先后發送到統一隊列中。所以RocketMQ

?

消息重復

造成消費重復的根本原因是網絡不可達,只要有網絡,這種網絡的不穩定因素就存在你無法規避。所以解決這個問題的最好辦法就是繞過它。這就變成了,消費端收到兩個一樣的消息后如何處理,而不是從發送端解決不發送2個一樣的消息。對于消費端的要求就是:

  • 消費端處理業務消息要保持冪等性,也就是同一個東西執行多次會得到相同結果

  • 保證每條消息都有唯一編號切保證消息處理成功與去重表的日志同時出現

第一條好理解,第二條就是利用一張日志表來記錄已經處理成功的消息ID,如果新到的消息ID已經存在表中那么就不再處理這個消息。第一條是在消費端實現的,不屬于消息系統的功能;第二條可以是消息系統實現也可以是業務端實現,處于對消息系統的吞吐量和高可用考慮最好還是由消費端去處理。所以這也就是RocketMQ不解決消息重復的原因。

轉自:http://blog.51cto.com/littledevil/2068474

? ? ? ? ? ?http://blog.51cto.com/littledevil/2068548

? ? ? ? ? ?http://blog.51cto.com/littledevil/2068718

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/448832.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/448832.shtml
英文地址,請注明出處:http://en.pswp.cn/news/448832.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C# JsonHelper類

記錄一下&#xff0c;方便下次用。 public class JsonHelper{#region Json/// <summary>/// JavaScriptSerializer/// </summary>/// <typeparam name"T"></typeparam>/// <param name"obj"></param>/// <returns&…

[譯】Redux入門教程(一)

前言 老外寫技術文章真是叼&#xff0c;這是國外的一個程序員寫的一個簡單易懂,循序漸進的Redux教程&#xff0c;本著共享的精神&#xff0c;就翻譯出來給大家一起看&#xff0c;文章最后有鏈接&#xff0c;不想看我翻譯的直接去看原文吧。 下面是原教程的英文目錄 這篇先更三分…

使用 Intellij Idea 打包 java 工程為可執行 jar 包

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 其實還有個簡單多了方法&#xff0c;見&#xff1a; 超簡單方法&#xff1a; Intellij Idea 把 java 工程打成可運行的 jar 步驟&#x…

QuickStart系列:docker部署之Gitlab本地代碼倉庫

gitlab是可以在本地搭建的使用git作為源代碼管理的倉庫。 運行環境&#xff1a; win10vmware14docker7docker 1. 使用命令拉取鏡像&#xff08;非必須&#xff0c;耗時比較久&#xff0c;這里以ce為準&#xff0c;ce是社區版&#xff0c;ee是企業版&#xff09;&#xff1a; do…

超簡單方法: Intellij Idea 把 java 工程打成可運行的 jar

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 找到 Intellij Idea 最下面的 Terminal 選項&#xff0c;并點擊進入該界面。 2. 在光標位置輸入命令&#xff1a;mvn clean 。清理…

LDAP-輕量級目錄訪問協議(統一認證)

概念 LDAP是輕量目錄訪問協議&#xff0c;英文全稱是Lightweight Directory Access Protocol&#xff0c;一般都簡稱為LDAP。 參考資料 LDAP概念和原理介紹 我花了一個五一終于搞懂了OpenLDAP LDAP-Apache Directory Studio使用&#xff08;創建DC.OU及用戶&#xff09; 轉載于…

kafka集群搭建(消息)

1、Kafka使用背景在我們大量使用分布式數據庫、分布式計算集群的時候&#xff0c;是否會遇到這樣的一些問題&#xff1a;我們想分析下用戶行為&#xff08;pageviews&#xff09;&#xff0c;以便我們設計出更好的廣告位我想對用戶的搜索關鍵詞進行統計&#xff0c;分析出當前的…

[轉]在Windows 下使用OpenCL

目前&#xff0c;NVIDIA和AMD的Windows driver均有支援OpenCL&#xff08;NVIDIA的正式版driver是從195.62版開始&#xff0c;而AMD則是從9.11版開始&#xff09;。NVIDIA的正式版driver中包含OpenCL.dll&#xff0c;因此可以直接使用。AMD到目前為止&#xff0c;則仍需要安裝其…

docker 之 Dockerfile 實踐

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 上一篇介紹了Dockerfile中使用的指令&#xff0c;現在開始進行指令實踐 先查看下本地的鏡像&#xff0c;選一個作為base image&#xf…

tomcat啟動后命令行日志中文亂碼

這是日志的編碼設置和窗體的編碼格式不一致。 將 conf\logging.properties 文件中的 UTF-8 改成 GBK 重啟tomcat &#xff08;右鍵cmd標題欄部分&#xff0c;可以查看cmd屬性&#xff09; 轉載于:https://www.cnblogs.com/Echiops/p/10974587.html

Coursera機器學習筆記(一) - 監督學習vs無監督學習

轉載 http://daniellaah.github.io/2016/Machine-Learning-Andrew-Ng-My-Notes-Week-1-Introduction.html 一. 監督學習 什么是監督學習? 我們來看看維基百科中給出的定義: 監督式學習&#xff08;英語&#xff1a;Supervised learning&#xff09;&#xff0c;是一個機器學習…

基于OpenCL的mean filter性能

1.對于一個標準的3*3 均值濾波&#xff0c;kernel代碼如下&#xff1a; 使用buffer/image緩沖對象 __kernel void filter(__global uchar4* inputImage, __global uchar4* outputImage, uint N) {int x get_global_id(0);int y get_global_id(1);int width get_global_size(…

Docker 實戰:編寫 Dockerfile

一、編譯鏡像 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 編譯鏡像 Dockerfile類似于Makfile&#xff0c;用戶使用docker build就可以編譯鏡像&#xff0c;使用該命令可以設置編譯…

dubbo-環境搭建,實現一個簡單地dubbo實例(附github地址)

一、建立maven模塊和provider、consumer、service子模塊&#xff0c;其中service是開發接口的模塊 建立一個maven模塊&#xff0c;不選擇樣板&#xff0c;直接next知道完成&#xff0c;建立三個子模塊,建立完后發現各個模塊的java目錄不是源目錄 右鍵——>make Directory as…

static 二次理解

當api底層用到static修飾的話&#xff0c;因為是類的&#xff0c;此容器中只有一份轉載于:https://blog.51cto.com/jiaxiaoxu/2394844

AMD 5XXX 系列顯卡的 peak bandwidth計算

在ATI Stream Computing Programming Guide中&#xff0c;例舉了AMD 5系列顯卡的參數信息。 我比較關注其中Peak bandwidths的計算&#xff0c;以便在opencl程序測試bandwidth利用率。 下面&#xff0c;我以5870為例&#xff0c;探討一下如何計算得到這些結果&#xff1a; L1 c…

Docker : Dockerfile 定制鏡像

使用 Dockerfile 定制鏡像 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 鏡像的定制實際上就是定制每一層所添加的配置、文件。如果我們可以把每一層修改、安裝、構建、操作的命令都寫…

動態規劃 最長上升子序列

題意&#xff1a;給出一個序列&#xff0c;求它的最長上升子序列的長度 題目鏈接&#xff1a;https://ac.nowcoder.com/acm/problem/26156 輸入:n代表長度&#xff0c;然后是一個字符串 分析&#xff1a;用dp[i]表示長度為i1的上升子序列末尾元素的最小值&#xff08;一開始初始…

解說redis中如何實現高可用

redis中為了實現高可用&#xff08;High Availability&#xff0c;簡稱HA&#xff09;&#xff0c;采用了如下兩個方式&#xff1a;主從復制數據。采用哨兵監控數據節點的運行情況&#xff0c;一旦主節點出現問題由從節點頂上繼續進行服務。主從復制redis中主從節點復制數據有全…

OpenCL memory object 之 Global memory (1)

這篇日志是學習AMD OpenCL文檔時候的總結。 OpenCL用memory object在host和device之間傳輸數據&#xff0c;memory object由runtime&#xff08;運行庫&#xff0c;driver的一部分&#xff09;來管理。 OpenCL中的內存對象包括buffer以及image&#xff0c;buffer是一維數據元素…