天天看點

讀懂這篇文章,你的阿裡技術面就可以過關了

在美國的大學課程中,101是所有課程中的第一門,是新生入學後的必修課程。阿裡巴巴中間件技術專家劉振東在上周的Apache RocketMQ開發者沙龍北京站的活動上,進行了主題為《ApacheRocketMQ 101》的分享,幫助開發者從0開始學習 Apache RocketMQ,除了一些基礎的入門内容外,還有很多是在社群未發表過的個人所感所悟,首次對外分享。分享内容包括RocketMQ的起源、RocketMQ概念模型、存儲模型、部署模型和最佳實踐總結,其中最佳實踐的内容是阿裡中間件技術類崗位的必考面試題。

讀懂這篇文章,你的阿裡技術面就可以過關了

嘉賓介紹:劉振東,阿裡巴巴中間件技術專家,Apache RocketMQ  PMC/Committer,2016年中間件性能挑戰賽亞軍,具有豐富的分布式系統設計和優化經驗,目前負責Apache RocketMQ新航道探索和創新。

一、RocketMQ的起源 

通常,每個産品的誕生都源于一個具體的需求或問題,RocketMQ也不例外。起初,産品的原型像一個巨石,把所有需要實作的程式和接口都羅列到一起。但随着公司業務的發展,所有的系統和功能都在這個巨石上開發,當覆寫幾百上千名開發人員的時候,瓶頸就出來了。這時候,就需要我們把系統進行分解。

讀懂這篇文章,你的阿裡技術面就可以過關了

圖釋:巨石 -> 分布式

分解後,就出現了上圖中的分布式架構,這類架構最大的特點就是解耦,而RocketMQ的異步解耦意味着底層的重構不會影響到上層應用的功能。RocketMQ另一個優勢是削峰填谷,在面臨流量的不确定性時,實作對流量的緩沖處理。此外,RocketMQ的順序設計特性使得RocketMQ成為一個天然的排隊引擎,例如,三個應用同時對一個背景引擎發起請求,排隊引擎的特性可以確定不會引起“撞車”事故。

二、RocketMQ的概念模型 

對于任何一款中間件産品而言,清晰的概念模型是幫助開發者正确了解使用它的關鍵。從RocketMQ的概念模型來看:Topic是用于存儲邏輯的位址的,Producer是資訊的發送,Consumer是資訊的接收者。

讀懂這篇文章,你的阿裡技術面就可以過關了

圖釋:最基本的概念模型

這隻是一個基礎的概念模型,在實際的生産中,結構會更複雜,例如我們需要對中間的Topic進行分區,出現多個有關聯的Topic,再如同一個資訊的發送方會有多個訂閱者,同一個需求方會有多個發送方,出現一對多、多對一的情況。

讀懂這篇文章,你的阿裡技術面就可以過關了

圖釋:擴充後的概念模型

上圖就是對Topic、Producer、Consumer擴充後的概念模型。RocketMQ中可以接觸到的所有概念都可以在這個概念模型圖中找到。左邊有兩個Producer,中間就是兩個分布式的Topic,用于存儲邏輯位址的兩個Topic中分别有兩個用于存儲實體存儲位址的Message Queue,Broker是實際部署過程的對應的一台裝置,右邊則是兩個Consumer,Consumer Group是代表兩個Consumer可共享互相之間的訂閱。不同的Consumer Group互相獨立。一句話總結就是不同的Group是廣播訂閱的,同一個Group則是負載訂閱的。圖中的連線表示各子產品之間的關系,例如Consumer Group A中的Consumer1對應着Message Queue0和Message Queue1的兩個隊列,分布在BrokerA這一台裝置上。

三、RocketMQ的存儲模型 

RocketMQ的消息的存儲是由ConsumeQueue和CommitLog 配合來完成的,ConsumeQueue中隻存儲很少的資料,消息主體都是通過CommitLog來進行讀寫。

讀懂這篇文章,你的阿裡技術面就可以過關了

圖釋:存儲模型

CommitLog:是消息主體以及中繼資料的存儲主體,對CommitLog建立一個ConsumeQueue,每個ConsumeQueue對應一個(概念模型中的)MessageQueue,是以隻要有Commit Log在,Consume Queue即使資料丢失,仍然可以恢複出來。

Consume Queue:是一個消息的邏輯隊列,存儲了這個Queue在CommitLog中的起始offset,log大小和MessageTag的hashCode。每個Topic下的每個Queue都有一個對應的ConsumerQueue檔案,例如Topic中有三個隊列,每個隊列中的消息索引都會有一個編号,編号從0開始,往上遞增。并由此一個位點offset的概念,有了這個概念,就可以對Consumer端的消費情況進行隊列定義。

四、RocketMQ的部署模型 

在實際的部署過程中,Broker是實際存儲消息的資料節點,Nameserver則是服務發現節點,Producer發送消息到某一個Topic,并給到某個Consumer用于消費的過程中,需要先請求Nameserver拿到這個Topic的路由資訊,即Topic在哪些Broker上有,每個Broker上有哪些隊列,拿到這些請求後再把消息發送到Broker中;相對的,Consumer在消費的時候,也會經曆這個流程。

讀懂這篇文章,你的阿裡技術面就可以過關了

圖釋:部署模型

五、RocketMQ最佳實踐總結 

這是我們在實踐過程的總結,同時我們也把其中一些普适性的總結作為阿裡中間件技術崗的面試題,目的是幫助大家更深刻的了解我們在設計分布式消息系統的一些思考和探索。

Q1:分布式消息系統中,如何避免消息重複?

造成消息重複的根本原因是:網絡不可靠。隻要通過網絡交換資料,就無法避免這個問題。是以解決這個問題的辦法就是繞過這個問題。那麼問題就變成了:如果消費端收到兩條一樣的消息,應該怎樣處理?

a. 消費端處理消息的業務邏輯保持幂等性;

b. 保證每條消息都有唯一編号且保證消息處理成功與去重表的日志同時出現。

通過幂等性,不管來多少條重複消息,可以實作處理的結果都一樣。再利用一張日志表來記錄已經處理成功的消息的ID,如果新到的消息ID已經在日志表中,那麼就可以不再處理這條消息,避免消息的重複處理。

Q2:順序消息擴容的過程中,如何在不停寫的情況下保證消息順序?

1. 成倍擴容,實作擴容前後,同樣的key,hash到原隊列,或者hash到新擴容的隊列;

2. 擴容前,記錄舊隊列中的最大位點;

3. 對于每個Consumer Group,保證舊隊列中的資料消費完,再消費新隊列,也即:先對新隊列進行禁讀即可;

Q3:分布式消息系統中,如何對消息進行重放?

消費位點就是一個數字,把Consumer Offset改一下就可以達到重放的目的了。

讀懂這篇文章,你的阿裡技術面就可以過關了

Apache RocketMQ部分開發者合影

原文釋出時間為:2018-11-05

本文作者:劉振東

本文來自雲栖社群合作夥伴“

技術瑣話

”,了解相關資訊可以關注“

”。