所謂天才,只不過是把別人喝咖啡的功夫都用在工作上了。
????????????????????????????????????????????????????????????????????????????????——魯迅
大綱

RocketMQ其他功能
1.消息軌跡
? ??源碼目錄下也有說明文檔:
????rocketmq-all-4.8.0-source-release\docs\cn\msg_trace\user_guide.md
(1)配置
? ??Broker 端服務器開啟配置:traceTopicEnable=true?

????RocketMQ 集群中每一個 Broker 節(jié)點均用于存儲 Client 端收集并發(fā)送過來的消息軌跡數(shù)據(jù)。因此,對于 RocketMQ 集群中的 Broker 節(jié)點數(shù)量并無要求和限制。
????對于消息軌跡數(shù)據(jù)量較大的場景,可以在 RocketMQ 集群中選擇其中一個 Broker 節(jié)點專用于存儲消息軌跡,使得用戶普通的消息數(shù)據(jù)與消息軌跡數(shù)據(jù)的物理 IO 完全隔離,互不影響。在該模式下,RockeMQ 集群中至少有兩個 Broker 節(jié)點,其中一個 Broker 節(jié)點定義為存儲消息軌跡數(shù)據(jù)的服務端。
(2)保存消息軌跡的Topic定義
? ??RocketMQ 的消息軌跡特性支持兩種存儲軌跡數(shù)據(jù)的方式:
????系統(tǒng)級的 TraceTopic
????在默認情況下,消息軌跡數(shù)據(jù)是存儲于系統(tǒng)級的 TraceTopic 中(其名稱為:RMQ_SYS_TRACE_TOPIC,隊列個數(shù)為 1)。該 Topic 在 Broker 節(jié)點啟動時,會自動創(chuàng)建出來(如上所敘,需要在 Broker 端的配置文件中將 traceTopicEnable 的開關變量設置為 true)。
????用戶自定義的 TraceTopic
????如果用戶不準備將消息軌跡的數(shù)據(jù)存儲于系統(tǒng)級的默認 TraceTopic,也可以自己定義并創(chuàng)建用戶級的 Topic 來保存軌跡(即為創(chuàng)建普通的 Topic用于保存消息軌跡數(shù)據(jù))。自定義的話需要在 Client 客戶端的處理的時候自定義的 TraceTopic。具體見案例。一般推薦使用系統(tǒng)及的 TraceTopic。
(3)案例
? ??代碼在 example 目錄下,tracemessage 目錄下。
????RocketMQ 在消息審核消費時采用對原來接口增加一個開關參數(shù)(enableMsgTrace)來實現(xiàn)消息軌跡是否開啟;并新增一個自定義參數(shù)(customizedTraceTopic)來實現(xiàn)用戶存儲消息軌跡數(shù)據(jù)至自己創(chuàng)建的用戶級 Topic。


????對于定義軌跡的主題,需要先創(chuàng)建這個主題才能收到消息,RocketMQ 不會自動創(chuàng)建該主題。




(4)關鍵屬性

(5)源碼解讀
? ??代碼實現(xiàn)的核心類是 AsyncTraceDispatcher
????org.apache.rocketmq.client.trace.AsyncTraceDispatcher
? ??記錄消息的軌跡主要是集中在消息發(fā)送前后、消息消費前后,可以通過 RokcetMQ 的 Hook 機制。通過如下兩個接口來定義鉤子函數(shù)

????SendMessageHook

ConsumeMessageHook

? ??通過實行上述兩個接口,可以實現(xiàn)在消息發(fā)送、消息消費前后記錄消息軌跡,為了不明顯增加消息發(fā)送與消息消費的時延,記錄消息軌跡最好使用 異步發(fā)送模式。
? ??核心步驟如下:
????1:遍歷收集的消息軌跡數(shù)據(jù)
????2:獲取存儲消息軌跡的 Topic
????3:對 TraceContext 進行編碼,這里是消息軌跡的傳輸數(shù)據(jù)。
????4:將編碼后的數(shù)據(jù)發(fā)送到 Broker 服務器。

2.權(quán)限控制
? ??在 RocketMQ4.4.0 版本升級中加入了 ACL 權(quán)限管控,ACL 是 access control list 的簡稱,俗稱訪問控制列表。訪問控制,基本上會涉及到用戶、資源、 權(quán)限、角色等概念。
????用戶的概念,即支持用戶名、密碼。
????資源:需要保護的對象,消息發(fā)送涉及的 Topic、消息消費涉及的消費組,應該進行保護,故可以抽象成資源。????
????權(quán)限:針對資源,能進行的操作。 角色:RocketMQ 中,只定義兩種角色:是否是管理員。
(1)配置
? ??acl 默認的配置文件名:plain_acl.yml,需要放在${ROCKETMQ_HOME}/store/config 目錄下
? ??需要使用 acl 必須在服務端開啟此功能,在 Broker 的配置文件中配置,aclEnable = true 開啟此功能
????RocketMQ 的權(quán)限控制存儲的默認實現(xiàn)是基于 yml 配置文件。用戶可以動態(tài)修改權(quán)限控制定義的屬性,而不需重新啟動 Broker 服務節(jié)點,因為Broker端有文件監(jiān)聽機制,每隔 500ms 監(jiān)聽、處理、加載文件的變更內(nèi)容。
????如果 ACL 與高可用部署(Master/Slave 架構(gòu))同時啟用,那么需要在 Broker Master 節(jié)點的${ROCKETMQ_HOME}/store/conf/plain_acl.yml 配置文件中 設置全局白名單信息,即為將 Slave 節(jié)點的 ip 地址設置至 Master 節(jié)點 plain_acl.yml 配置文件的全局白名單中。

(2)案例實戰(zhàn)
? ??在 Broker 的配置文件中配置,aclEnable = true 開啟此功能

? ? 代碼得加入一個返回 RPCHook 的方法

????如果權(quán)限受限制:

????加入權(quán)限對應用戶:


????發(fā)送成功。
????很多時候像控制臺配置了后會報錯。

????把全局的白名單打開。

常見問題
1.MQ百萬消息積壓處理
? ??發(fā)生了線上故障,幾千萬條數(shù)據(jù)在 MQ 里積壓很久。是修復 consumer 的問題,讓他恢復消費速度,然后等待幾個小時消費完畢?這是個解決方案。 不過有時候我們還會進行臨時緊急擴容。
????一個消費者一秒是 1000 條,一秒 3 個消費者是 3000 條,一分鐘是 18 萬條。1000 多萬條,所以如果積壓了幾百萬到上千萬的數(shù)據(jù),即使消費者恢復了,也需要大概 1 小時的時間才能恢復過來。
????一般如果消息不重要的話就在 consume 上直接釋放掉。
????如果 topic 的 messageQueue 設置的比較多,比如設置了 20 個,consume 實例只有 4 個,那么每個 consume 實例對應 5 個 messageQueue,這個時候可以申請臨時加機器,增加 consume 實例為 20 個,達到快速消費的目的。
????如果 messageQueue 設置的比較少,比如只設置了 4 個,那么這個時候就不能通過加 consume 機器來解決了,這時候就需要修改消費者代碼了,不再消費者消費,而是把要消費的消息放到 mq 的另一個 topic 中,這個 topic 設置 20 個 messageQueue,對應 20 個 consume 實例,進行消費。
2.消息冪等
(1)消息重復的場景
? ?生產(chǎn)者
? ??重試機制導致的問題,消息成功發(fā)送到 MQ 中,但 MQ 因網(wǎng)絡原因未能成功返回,導致重試機制重復發(fā)送到 MQ 。
? ?消費端
? ??手動提交 offset 未完成
消費者成功消費完消息,未返回 consume_commit 時,系統(tǒng)重啟|系統(tǒng)宕機,MQ 重新發(fā)送消息到同消息組其他消費者機器,導致消息重復。
(2)什么是冪等性
? ??對于消息接收端的情況,冪等的含義是采用同樣的輸入多次調(diào)用處理函數(shù),得到同樣的結(jié)果。例如,一個 SQL 操作:update stat_table set count= 10 where id =1
????這個操作多次執(zhí)行,id 等于 1 的記錄中的 count 字段的值都為 10,這個操作就是冪等的,我們不用擔心這個操作被重復。
????再來看另外一個 SQL 操作:update stat_table set count= count +1 where id= 1;
????這樣的 SQL 操作就不是冪等的,一旦重復,結(jié)果就會產(chǎn)生變化。
(3)MVCC
? ??多版本并發(fā)控制,樂觀鎖的一種實現(xiàn),在生產(chǎn)者發(fā)送消息時進行數(shù)據(jù)更新時需要帶上數(shù)據(jù)的版本號,消費者去更新時需要去比較持有數(shù)據(jù)的版本號, 版本號不一致的操作無法成功。例如博客點贊次數(shù)自動+1 的接口:
????public boolean addCount(Long id, Long version);
????update blogTable set count= count+1,version=version+1 where id=321 and version=123
????每一個 version 只有一次執(zhí)行成功的機會,一旦失敗了生產(chǎn)者必須重新獲取數(shù)據(jù)的最新版本號再次發(fā)起更新。
(4)去重表
? ??利用數(shù)據(jù)庫表單的特性來實現(xiàn)冪等,常用的一個思路是在表上構(gòu)建唯一性索引,保證某一類數(shù)據(jù)一旦執(zhí)行完畢,后續(xù)同樣的請求不再重復處理了(利 用一張日志表來記錄已經(jīng)處理成功的消息的 ID,如果新到的消息 ID 已經(jīng)在日志表中,那么就不再處理這條消息。)
????利用 RocketMQ 的 key 值
????以電商平臺為例子,電商平臺上的訂單 id 就是最適合的 token。當用戶下單時,會經(jīng)歷多個環(huán)節(jié),比如生成訂單,減庫存,減優(yōu)惠券等等。每一個環(huán)節(jié)執(zhí)行時都先檢測一下該訂單 id 是否已經(jīng)執(zhí)行過這一步驟,對未執(zhí)行的請求,執(zhí)行操作并緩存結(jié)果,而對已經(jīng)執(zhí)行過的 id,則直接返回之前的執(zhí)行結(jié)果,不做任何操作。這樣可以在最大程度上避免操作的重復執(zhí)行問題,緩存起來的執(zhí)行結(jié)果也能用于事務的控制等。
RocketMQ性能優(yōu)化
1.JVM層面
(1)STW
監(jiān)控暫停
?????rocketmq-console 這個是官方提供了一個 WEB 項目,可以查看 rocketmq數(shù)據(jù)和執(zhí)行一些操作。但是這個監(jiān)控界面又沒有權(quán)限控制,并且還有一些消 耗性能的查詢操作,如果要提高性能,建議這個可以暫停。
????一般的公司在運維方面會有專門的監(jiān)控組件,如zabbix 會做統(tǒng)一處理。
????或者是簡單的shell命令
????監(jiān)控的方式有很多,比如簡單點的,我們可以寫一個shell 腳本,監(jiān)控執(zhí)行rocketmq Java進程的存活狀態(tài),如果rocketmq crash 了,發(fā)送告警。
消除偏向鎖
? ??大家了解,在 JDK1.8 sync 有偏向鎖,但是在 RocketMQ 都是多線程的執(zhí)行,所以競爭比較激烈,建議把偏向鎖取消,以免沒有必要的開銷。
????-XX:-UseBiasedLocking: 禁用偏向鎖
(2)垃圾回收
? ??RocketMQ 推薦使用 G1 垃圾回收器。
????-Xms8g -Xmx8g -Xmn4g:這個就是很關鍵的一塊參數(shù)了,也是重點需要調(diào)整的,就是默認的堆大小是 8g 內(nèi)存,新生代是 4g 內(nèi)存。
? ??如果是內(nèi)存比較大,比如有 48g 的內(nèi)存,所以這里完全可以給他們翻幾倍,比如給堆內(nèi)存 20g,其中新生代給 10g,甚至可以更多些,當然要留一些內(nèi)存給操作系統(tǒng)來用
????-XX:+UseG1GC -XX:G1HeapRegionSize=16m:這幾個參數(shù)也是至關重要的,這是選用了G1垃圾回收器來做分代回收,對新生代和老年代都是用G1來回收。這里把G1的region大小設置為了16m,這個因為機器內(nèi)存比較多,所以region 大小可以調(diào)大一些給到16m,不然用2m的region, 會導致region數(shù)量過多。
????-XX:G1ReservePercent=25:這個參數(shù)是說,在 G1 管理的老年代里預留 25%的空閑內(nèi)存,保證新生代對象晉升到老年代的時候有足夠空間,避免老年代內(nèi)存都滿了,新生代有對象要進入老年代沒有充足內(nèi)存了。默認值是 10%,略微偏少,這里 RocketMQ 給調(diào)大了一些。
????-XX:initiatingHeapOccupancyPercent= :30:這個參數(shù)是說,當堆內(nèi)存的使用率達到 30%之后就會自動啟動 G1 的并發(fā)垃圾回收,開始嘗試回收一些垃圾對象。默認值是 45%,這里調(diào)低了一些,也就是提高了 GC 的頻率,但是避免了垃圾對象過多,一次垃圾回收耗時過長的問題。
????-XX:-OmitStackTraceInFastThrow:這個參數(shù)是說,有時候 JVM 會拋棄-些異常堆棧信息,因此這個參數(shù)設置之后,就是禁用這個特性,要把完整的異常堆棧信息打印出來。
????-XX:+AIwaysPreTouch:這個參數(shù)的意思是我們剛開始指定 JVM 用多少內(nèi)存,不會真正分配給他,會在實際需要使用的時候再分配給他。
????所以使用這個參數(shù)之后,就是強制讓 JVM 啟動的時候直接分配我們指定的內(nèi)存,不要等到使用內(nèi)存的時候再分配。
????-XX:MaxDirectMemorySize=15g:這是說 RocketMQ 里大量用了 NIO 中的 direct buffer,這里限定了 direct buffer 最多申請多少,如果你機器內(nèi)存比較大,可以適當調(diào)大這個值,不了解 direct buffer 是什么,可以自己查看 JVM 三期。
????-XX:-UseLargePages:這個參數(shù)的意思是禁用大內(nèi)存頁,某些情況下會導致內(nèi)存浪費或?qū)嵗裏o法啟動。默認啟動。
2.操作系統(tǒng)層面
(1)基本參數(shù)

? ??vm.overcommit_memory=1
????是否允許內(nèi)存的過量分配
????當為 0 的時候,當用戶申請內(nèi)存的時候,內(nèi)核會去檢查是否有這么大的內(nèi)存空間
????當為 1 的時候,內(nèi)核始終認為,有足夠大的內(nèi)存空間,直到它用完了為止
????當為 2 的時候,內(nèi)核禁止任何形式的過量分配內(nèi)存
????vm.swappiness=10
????swappiness=0????僅在內(nèi)存不足的情況下,當剩余空閑內(nèi)存低于 vm.min_free_kbytes limit 時,使用交換空間
????swappiness=1????內(nèi)核版本 3.5 及以上、Red Hat 內(nèi)核版本 2.6.32-303 及以上,進行最少量的交換,而不禁用交換
????swappiness=10????當系統(tǒng)存在足夠內(nèi)存時,推薦設置為該值以提高性能
????swappiness=60????默認值
????swappiness=100????內(nèi)核將積極的使用交換空間
????vm.max_max_count=655360
????定義了一個進程能擁有的最多的內(nèi)存區(qū)域,默認為 65536
????ulimit=1000000
????limits.conf 設置用戶能打開的最大文件數(shù).
????1、查看當前大小
????ulimit -a

????2、臨時修改
????ulimit -n 1000000

? ??3、永久修改
????vim /etc/security/limits.conf

(2)NIC
? ??????一個請求到 RocketMQ 的應用,一般會經(jīng)過網(wǎng)卡、內(nèi)核空間、用戶空間。

? ? 網(wǎng)卡
? ??網(wǎng)絡接口控制器(英語:network interface controller,NIC)
? ??因 Ring Buffer 寫滿導致丟包的情況很多。當業(yè)務流量過大且出現(xiàn)網(wǎng)卡丟包的時候,建議調(diào)整 Ring Buffer 的大小,這個大小的設置一定程度上是可以緩解丟包的狀況。
(3)Kernel

中斷聚合
????在中斷(IRQ),
????在操作系統(tǒng)級別,是可以做軟中斷聚合的優(yōu)化。
? ??什么是中斷?
? ??舉例,假如你是一位開發(fā)同學,和你對口的產(chǎn)品經(jīng)理一天有 10 個小需求需要讓你幫忙來處理。她對你有兩種中斷方式:?
????第一種:產(chǎn)品經(jīng)理想到一個需求,就過來找你,和你描述需求細節(jié),然后讓你幫忙來改。
????第二種:產(chǎn)品經(jīng)理想到需求后,不來打擾你,等攢夠 5 個來找你一次,你集中處理。
????我們現(xiàn)在不考慮及時性,只考慮你的工作整體效率,你覺得那種方案下你的工作效率會高呢?或者換句話說,你更喜歡哪一種工作狀態(tài)呢? 很明顯,只要你是一個正常的開發(fā),都會覺得第二種方案更好。對人腦來講,頻繁的中斷會打亂你的計劃,你腦子里剛才剛想到一半技術(shù)方案可能也就廢了。當產(chǎn)品經(jīng)理走了以后,你再想撿起來剛被中斷之前的工作的時候,很可能得花點時間回憶一會兒才能繼續(xù)工作。
????對于 CPU 來講也是一樣,CPU 要做一件新的事情之前,要加載該進程的地址空間,load 進程代碼,讀取進程數(shù)據(jù),各級別 cache 要慢慢熱身。因此如果能適當降低中斷的頻率,多攢幾個包一起發(fā)出中斷,對提升 CPU 的工作效率是有幫助的。所以,網(wǎng)卡允許我們對硬中斷進行合并。
網(wǎng)卡隊列 CPU 綁定
? ??現(xiàn)在的主流網(wǎng)卡基本上都是支持多隊列的,我們可以通過將不同的隊列分給不同的CPU核心來處理,從而加快Linux內(nèi)核處理網(wǎng)絡包的速度。這是最為有用的一個優(yōu)化手段。
????每一個隊列都有一個中斷號,可以獨立向某個CPU核心發(fā)起硬中斷請求,讓CPU來poll包。通過將接收進來的包被放到不同的內(nèi)存隊列里,多個CPU就可以同時分別向不同的隊列發(fā)起消費了。這個特性叫做 RSS(Receive Side Scaling,接收端擴展)。通過ethtool工具可以查看網(wǎng)卡的隊列情況。
關閉 IRQBalance
? ??IRQBalance 主要功能是可以合理的調(diào)配使用各個CPU核心,特別是對于目前主流多核心的CPU,簡單的說就是能夠把壓力均勻的分配到各個CPU核心上,對提升性能有很大的幫助。
? ??但實際中往往影響 cpu 的使用均衡,建議服務器環(huán)境中關閉。
net.core.dev_weight
? ??每個 CPU 一次 NAPI 中斷能夠處理網(wǎng)絡包數(shù)量的最大值,可以根據(jù)實際情況調(diào)整。
TCP NODEALY
? ??Nagle算法用于對緩沖區(qū)內(nèi)的一定數(shù)量的消息進行自動連接。該處理過程(稱為Nagling),通過減少必須發(fā)送的封包的數(shù)量,提高了網(wǎng)絡應用 程序系統(tǒng)的效率。(Nagle雖然解決了小封包問題,但也導致了較高的不可預測的延遲,同時降低了吞吐量。)
? ??RocketMQ 通訊層已經(jīng)禁止了


緩沖區(qū)調(diào)整

隊列大小調(diào)整

我是嬈疆_蚩夢,讓堅持成為一種習慣,感謝各位大佬的:點贊、收藏和評論,我們下期見!