<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          3萬字聊聊什么是RocketMQ(三)

          共 5049字,需瀏覽 11分鐘

           ·

          2022-04-06 13:28

          大家好,我是Leo。

          上一篇我們介紹了

          1. MQ分布式事務的相關實現(xiàn)
          2. MQ消息丟失,一致性問題在生產(chǎn),存儲,消費階段如何解決
          3. 消息重發(fā)之后,如何避免重復消費

          繼上篇RocketMQ技術總結二,這篇主要介紹一下

          1. 消息積壓問題如何處理
          2. 閱讀源碼的小技巧
          3. 異步方案提升系統(tǒng)性能
          4. MQ的緩存策略

          277cde559492e392cb0ffae88760ff39.webp

          基礎知識系列

          3萬字聊聊什么是MySQL(初篇)

          3萬字聊聊什么是Redis(完結篇)

          3萬字聊聊什么是RocketMQ (二)

          2萬字聊聊什么是秒殺系統(tǒng)(中)

          大廠面試系列

          4萬字聊聊阿里二面,保證你看不完

          聊聊Redis面試題

          本章概括

          0fda65e48633eddf9c207f30cf9fc148.webp

          異步方案那里可以暫時一筆帶過,后續(xù)寫實戰(zhàn)的時候會詳細深入的

          入手源碼那里,根據(jù)自己對未來的發(fā)展規(guī)劃選擇性翻閱吧。

          消息積壓問題

          什么是消息積壓

          消息積壓是使用MQ消息隊列系統(tǒng)中,最常見的一種性能問題。如下圖所示,當生產(chǎn)端的生產(chǎn)效率大于消費端的消費效率就會造成消息處理不完的情況,也就叫 “消息積壓”。

          b59f27015c06dbf9b6a1236103951516.webp

          消息積壓應對方案(一)

          第一種方案主要是優(yōu)化生產(chǎn)端,消費端的處理能力。(消息隊列你就別優(yōu)化了,那么牛逼的團隊設計出那么好的產(chǎn)品不會出問題的)

          所以?我們只需要處理如何與消息隊列配合,達到一個最佳的性能就夠了

          對于生產(chǎn)端來說,并不會影響性能。因為一般生產(chǎn)端都是先執(zhí)行自己的業(yè)務程序之后,再生產(chǎn)消息到MQ的。如果說,你的代碼發(fā)送消息的性能上不去,你需要優(yōu)先檢查一下,是不是發(fā)消息之前的業(yè)務邏輯耗時太多導致的

          我們之前在講生產(chǎn)端發(fā)送消息的過程中,假設這一次交互的平均耗時1ms,我們把這1ms的時間分解開,主要包括下列幾項

          1. 發(fā)送前的準備數(shù)據(jù),序列化數(shù)據(jù),構造請求等耗時。也就是生產(chǎn)端在發(fā)送網(wǎng)絡請求之間的耗時
          2. 發(fā)送消息和返回響應在網(wǎng)絡傳輸中的耗時
          3. Broker處理消息的耗時

          如果是單線程發(fā)送,每次只發(fā)送 1 條消息,那么每秒只能發(fā)送 1000ms / 1ms * 1 條 /ms = 1000 條 消息,這種情況下并不能發(fā)揮出消息隊列的全部實力。

          無論是增加每次發(fā)送消息的批量大小,還是增加并發(fā),都能成倍地提升發(fā)送性能。至于到底是選擇批量發(fā)送還是增加并發(fā),主要取決于生產(chǎn)端程序的業(yè)務性質(zhì)。

          復習鏈接?生產(chǎn)端發(fā)送消息過程


          對于消費端來說,大部分的問題應該都是出在這里的。主要的調(diào)優(yōu)點也是在這個位置。

          如果消費端的性能延時只是暫時的,那問題不大,只要消費端的性能恢復之后,超過生產(chǎn)端的性能,那積壓的消息是可以逐漸被消化掉的。

          要是消費速度一直比生產(chǎn)速度慢,時間長了,整個系統(tǒng)就會出現(xiàn)問題,要么,消息隊列的存儲被填滿無法提供服務,要么消息丟失,這對于整個系統(tǒng)來說都是嚴重故障。所以,我們在設計系統(tǒng)的時候,一定要保證消費端的消費性能要高于生產(chǎn)端的發(fā)送性能,這樣的系統(tǒng)才能健康的持續(xù)運行。

          除了優(yōu)化業(yè)務性能,也可以對消費端進行水平擴容,增加消費端的并發(fā)數(shù)從而達到總體的消費性能。在擴容 Consumer 的實例數(shù)量的同時, 必須同步擴容主題中的分區(qū)(也叫隊列)數(shù)量,確保 Consumer 的實例數(shù)和分區(qū)數(shù)量是相等的。?如下圖所示。

          61380fa5e11e9acf9b4ae4916343b7ca.webp

          如果 Consumer 的實例數(shù)量超過分區(qū)數(shù)量,這樣的擴容實際上是沒有效果的。原因 我們之前講過,因為對于消費者來說,在每個分區(qū)上實際上只能支持單線程消費

          消息積壓應對方案(二)

          第二種方案應對的業(yè)務場景是,系統(tǒng)正常運轉時,不會出現(xiàn)消息積壓問題。但是某一時刻,突然就開始積壓并且持續(xù)上漲。

          這種問題還是比較糾結的,擴容的話,一般情況下是不需要的,不擴容的話某一刻又擋不住。。。。

          遇到這樣的場景無需就是兩種原因,要不生產(chǎn)變快了,要不消費變慢了。我們可以通過監(jiān)控程序觀察一下數(shù)據(jù)情況再定位某種原因。

          最后實在沒辦法可以將系統(tǒng)進行降級,通過關閉一些不重要的業(yè)務,減少生產(chǎn)方發(fā)送的數(shù)據(jù)量,最低限度的讓系統(tǒng)的熱賣業(yè)務還能正常運轉。

          重復消費也會拖慢整個系統(tǒng)的消費速度。

          關于重復消費可以參考?重復消費解決方案

          如何入手學習源碼

          最核心的一點就是查看?官方文檔

          官方文檔是所有技術中 最權威,最齊全的一個資料聚集地

          有些翻譯中文的網(wǎng)站,可能會做到更新不及時,所以還是建議直接看英文文檔,借助翻譯即可。也可以鍛煉英文水平

          首先要?掌握這個技術的整體結構,有哪些功能特性,涉及到的關鍵技術、實現(xiàn)原理和生態(tài)系統(tǒng)?等等。掌握了這些,對它的整體有了一定了解,然后再去看它的源代碼,就會非常通暢了。比如我之前做的MySQL技術分享如下圖。

          63a1e9d5860cc8ee1905bc01e6712991.webp

          Redis的技術分享如下圖

          9335919e3fb5e8ab7bb2098b1f1455f9.webp

          RocketMQ的技術分享還沒畫,可以暫時參考一下官方

          d8325b569b48ca6806d085edff3f0c43.webp

          我覺得學習這個東西最好的老師是興趣。所以一定要帶著問題去讀源碼。比如

          1. RocketMQ的消息是怎么寫到文件中的?(肯定不會像我們業(yè)務程序那樣直接寫的)
          2. RocketMQ的重發(fā)機制是怎么實現(xiàn)的?
          3. RocketMQ的確認機制是怎么實現(xiàn)的?
          4. RocketMQ的分布式的實現(xiàn)源碼是怎么樣的?
          5. RocketMQ的消息不丟失是否和MySQL那樣有binlog,redo log,是否和Redis那樣有RDB,AOF呢?

          上述問題反正是我當下最想知道的,但是不要操之過急,學懂整體后再深入。

          一定不要直接從main里看,程序跟書是不一樣的,書是由人學懂之后,整理的一個先后學習順序。而程序是一個網(wǎng)狀結構,是一個功能一個功能的實現(xiàn)

          這上述也是我接下來學習源碼的方法。源碼分析的話,我的想法是等我學完RocketMQ的基礎原理,我會從第一篇文章涉及到的知識點,進入源碼閱讀分析整理

          MySQL,Redis就算了,打算發(fā)力MQ

          異步方案提升系統(tǒng)性能

          這里先簡單聊一下思想,后續(xù)會用代碼案例實現(xiàn)。

          異步執(zhí)行

          簡單的說,異步思想就是,當我們要執(zhí)行一項比較耗時的操作時,不去等待操作結束,而是給這個操作一個命令:“當操作完成后,接下來去執(zhí)行什么。”

          使用異步編程模型,雖然并不能加快程序本身的速度,但可以減少或者避免線程等待,只用很少的線程就可以達到超高的吞吐能力。

          同時我們也需要注意到異步模型的問題:相比于同步實現(xiàn),異步實現(xiàn)的復雜度要大很多,代 碼的可讀性和可維護性都會顯著的下降。雖然使用一些異步編程框架會在一定程度上簡化異 步開發(fā),但是并不能解決異步模型高復雜度的問題。

          異步性能雖好,但一定不要濫用,只有類似在像消息隊列這種業(yè)務邏輯簡單并且需要超高吞 吐量的場景下,或者必須長時間等待資源的地方,才考慮使用異步模型。如果系統(tǒng)的業(yè)務邏 輯比較復雜,在性能足夠滿足業(yè)務需求的情況下,采用符合人類自然的思路且易于開發(fā)和維 護的同步模型是更加明智的選擇。

          異步網(wǎng)絡

          傳統(tǒng)的同步網(wǎng)絡 IO,一般采用的都是一個線程對應一個 Channel 接收數(shù)據(jù),很難支持高并 發(fā)和高吞吐量。這個時候,我們需要使用異步的網(wǎng)絡 IO 框架來解決問題。

          Netty 和 NIO 是兩種異步網(wǎng)絡框架。

          Netty 自動地解決了線程控制、緩存管理、連接管理這些問題,用戶只需要實現(xiàn)對應的 Handler 來處理收到的數(shù)據(jù)即可。

          NIO 是更加底層的 API,它提供了 Selector 機制,用單個線程同時管理多個連接,解決了多路 復用這個異步網(wǎng)絡通信的核心問題。

          0e137af58410620dfecf23c7a74a1163.webp

          以上是 IO、BIO、NIO的發(fā)展,流程圖

          緩存策略

          緩存策略的出現(xiàn),主要解決的就是如何減少與磁盤IO交互,提升系統(tǒng)性能。對于持久化來說,肯定還是要存磁盤的。所以我們必須保證最大的幾率命中緩存,同時也要減少與磁盤IO的交互。

          一般來說 SSD 每秒鐘可以讀寫幾千次,如果說我們的程序在處理業(yè)務請求的時候直接來讀寫磁盤,假設處理每次請求需要讀寫 3~5 次,即使每次請求的數(shù)據(jù)量不大,你的程序最多每秒也就 能處理 1000 次左右的請求。而內(nèi)存的隨機讀寫速度是磁盤的 10 萬倍!所以,使用內(nèi)存作為緩存來加速應用程序的訪問速度,是幾乎所有高性能系統(tǒng)都會采用的方法。

          只讀與讀寫緩存的抉擇

          使用緩存,首先你就會面臨選擇讀緩存還是讀寫緩存的問題。他們唯一的區(qū)別就是,在更新數(shù)據(jù)的時候,是否經(jīng)過緩存

          讀寫緩存:?它是一種犧牲數(shù)據(jù)一致性換取性能的設計,天然是不可靠的。

          5578f564c1ff86c1a659f1810f1363ee.webp

          為什么說他是不可靠的呢?可以從上圖中看出,寫入數(shù)據(jù)到PageCache時,并不是同步寫入的,而是異步,如果在這段期間,還沒開始異步寫入時,服務器直接宕機了,就丟失了數(shù)據(jù)。

          如果說我們?nèi)斯げ僮鳎瑘?zhí)行一次sync。這樣也就失去了緩存的意義

          緩存的意義不就是減少與磁盤IO的交互嘛

          寫緩存的實現(xiàn)是非常復雜的。應用程序不停地更新 PageCache 中的數(shù)據(jù),操作系統(tǒng) 需要記錄哪些數(shù)據(jù)有變化,同時還要在另外一個線程中,把緩存中變化的數(shù)據(jù)更新到磁盤文 件中。在提供并發(fā)讀寫的同時來異步更新數(shù)據(jù),這個過程中要保證數(shù)據(jù)的一致性,并且有非常好的性能,實現(xiàn)這些真不是一件容易的事兒。

          所以一般?推薦使用只讀緩存。

          如何保持緩存數(shù)據(jù)新鮮

          上面提到了推薦使用只讀緩存,對于只讀緩存來說,緩存中的數(shù)據(jù)來源只有一個途徑,就是從磁盤上來。當數(shù)據(jù)需要更新的時候,磁盤中的數(shù)據(jù)和緩存中的副本都需要進行更新。我們知道在分布式系統(tǒng)中,除非是使用事務或者一些分布式一致性算法來保證數(shù)據(jù)一致性,否則,由于節(jié)點宕機、網(wǎng)絡傳輸故 障等情況的存在,我們是無法保證緩存中的數(shù)據(jù)和磁盤中的數(shù)據(jù)是完全一致的。

          我們要做的就是盡可能最大的保證數(shù)據(jù)同步。最省心,代價最大的就是采用分布式事務來解決了。

          另一種簡單的方式就是采用Redis那種過期key的方式實現(xiàn),數(shù)據(jù)過期以后即使它還存在緩存中,我們也認為它不再有效,需要從 磁盤上再次加載這條數(shù)據(jù),這樣就變相地實現(xiàn)了數(shù)據(jù)更新。

          還是根據(jù)業(yè)務吧。比如微信頭像修改后的實時顯示,郵件的延遲幾秒鐘接收都可以采用過期key的方式

          如果是那種交易類系統(tǒng),對數(shù)據(jù)一致性比較敏感的可以采用犧牲性能來決定一致性。

          緩存的置換策略

          在使用緩存的過程中,除了要考慮數(shù)據(jù)一致性的問題,你還需要關注的另一個重要的問題是,在內(nèi)存有限的情況下,要優(yōu)先緩存哪些數(shù)據(jù),讓緩存的命中率最高

          當應用程序要訪問某些數(shù)據(jù)的時候,如果這些數(shù)據(jù)在緩存中,那直接訪問緩存中的數(shù)據(jù)就可以了,這次訪問的速度是很快的,這種情況我們稱為一次緩存命中;如果這些數(shù)據(jù)不在緩存中,那只能去磁盤中訪問數(shù)據(jù),就會比較慢。這種情況我們稱為“緩存穿透”。顯然,緩存的命中率越高,應用程序的總體性能就越好。

          那用什么樣的策略來選擇緩存的數(shù)據(jù),能使得緩存的命中率盡量高一些呢?

          如果你的系統(tǒng)是那種可以預測未來訪問哪些數(shù)據(jù)的系統(tǒng),比如說,有的系統(tǒng)它會定期做數(shù)據(jù)同步,每次同步的數(shù)據(jù)范圍都是一樣的,像這樣的系統(tǒng),緩存策略很簡單,就是你要訪問什么數(shù)據(jù),就緩存什么數(shù)據(jù),甚至可以做到百分之百的命中。

          但是,大部分系統(tǒng),它并沒有辦法準確地預測未來會有哪些數(shù)據(jù)會被訪問到,所以只能使用一些策略來盡可能地提高緩存命中率。

          一般來說,我們都會在數(shù)據(jù)首次被訪問的時候,順便把這條數(shù)據(jù)放到緩存中。隨著訪問的數(shù)據(jù)越來越多,總有把緩存占滿的時刻,這個時候就需要把緩存中的一些數(shù)據(jù)刪除掉,以便存放新的數(shù)據(jù),這個過程稱為緩存置換。

          到這里,問題就變成了:當緩存滿了的時候,刪除哪些數(shù)據(jù),才能會使緩存的命中率更高一 些,也就是采用什么置換策略的問題。

          命中率最高的置換策略,一定是根據(jù)你的業(yè)務邏輯,定制化的策略。比如,你如果知道某些數(shù)據(jù)已經(jīng)刪除了,永遠不會再被訪問到,那優(yōu)先置換這些數(shù)據(jù)肯定是沒問題的。再比如,你的系統(tǒng)是一個有會話的系統(tǒng),你知道現(xiàn)在哪些用戶是在線的,哪些用戶已經(jīng)離線,那優(yōu)先置換那些已經(jīng)離線用戶的數(shù)據(jù),盡量保留在線用戶的數(shù)據(jù)也是一個非常好的策略。

          另外一個選擇,就是?使用通用的置換算法。一個最經(jīng)典也是最實用的算法就是 LRU 算法, 也叫最近最少使用算法。這個算法它的思想是,最近剛剛被訪問的數(shù)據(jù),它在將來被訪問的 可能性也很大,而很久都沒被訪問過的數(shù)據(jù),未來再被訪問的幾率也不大

          基于這個思想,LRU 的算法原理非常簡單,它總是把最長時間未被訪問的數(shù)據(jù)置換出去。你別看這個 LRU 算法這么簡單,它的效果是非常非常好的。

          可以參考Redis的的LRU文章,實現(xiàn)原理都是差不多的?LRU算法的實現(xiàn)

          充電分享

          少年有夢,不應止于心動,更應付出行動,用自己的關,照亮自己的路,努力追上那個曾經(jīng)被賦予厚望的自己

          —— 致自己,致各位追夢的你們

          86061ddf0034f833bdf61308825b0ff9.webp

          結尾

          有些不懂的地方或者不對的地方,麻煩各位指出,一定修改優(yōu)化!

          非常歡迎大家加我個人微信有關后端方面的問題我們在群內(nèi)一起討論!?我們下l,。;期再見!

          長按上方掃碼二維碼,加我微信,拉你進群

          927f726aa28d28179d61e4cff78edf61.webp


          瀏覽 72
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  枕瑶钗十三回兴云弄雨又春风 | 欧美成人在线视频 | 国产91深喉口爆在线观看 | 国产91av在线 | 台湾高清无码视频在线观看 |