前言
現今時代,系統越來越複雜,資料來越多,系統間的互動也就變得越來越重要,同時也變得越來越困難。而消息中間件在其中起到了一個中間橋梁的重要作用。是以,面試中也經常會被問到消息中間件相關的問題。從其使用到其原理設計,都會是面試官感興趣的一個點。本場小編就以zookeeper / RocketMQ 為例,簡單介紹消息中間件并在其中穿插面試官常會提及的消息中間件相關的問題。
Zookeeper
1. ZooKeeper 是什麼?
ZooKeeper 是一個開放源碼的分布式協調服務,它是叢集的管理者,監視着叢集中各個節點的狀态根 據節點送出的回報進行下一步合理操作。最終,将簡單易用的接口和性能高效、功能穩定的系統提供給使用者。
分布式應用程式可以基于 Zookeeper 實作諸如資料釋出/訂閱、負載均衡、命名服務、分布式協調/通知、叢集管理、Master 選舉、分布式鎖和分布式隊列等功能。
Zookeeper 保證了如下分布式一緻性特性:
(1)順序一緻性
(2)原子性
(3)單一視圖
(4)可靠性
(5)實時性(最終一緻性)
用戶端的讀請求可以被叢集中的任意一台機器處理,如果讀請求在節點上注冊了監聽器,這個監聽器也 是由所連接配接的 zookeeper 機器來處理。對于寫請求,這些請求會同時發給其他 zookeeper 機器并且達成一緻後,請求才會傳回成功。是以,随着 zookeeper 的叢集機器增多,讀請求的吞吐會提高但是寫 請求的吞吐會下降。
有序性是 zookeeper 中非常重要的一個特性,所有的更新都是全局有序的,每個更新都有一個唯一的時間戳,這個時間戳稱為 zxid(Zookeeper Transaction Id)。而讀請求隻會相對于更新有序,也就是 讀請求的傳回結果中會帶有這個zookeeper 最新的 zxid。
2. ZooKeeper 提供了什麼?
(1)檔案系統
(2)通知機制
3.Zookeeper 檔案系統
Zookeeper 提供一個多層級的節點命名空間(節點稱為 znode)。與檔案系統不同的是,這些節點都可以設定關聯的資料,而檔案系統中隻有檔案節點可以存放資料而目錄節點不行。 Zookeeper 為了保證高吞吐和低延遲,在記憶體中維護了這個樹狀的目錄結構,這種特性使得Zookeeper 不能用于存放大量的資料,每個節點的存放資料上限為1M。
4. ZAB 協定?
ZAB 協定是為分布式協調服務 Zookeeper 專門設計的一種支援崩潰恢複的原子廣播協定。 ZAB 協定包括兩種基本的模式:崩潰恢複和消息廣播。 當整個 zookeeper 叢集剛剛啟動或者 Leader 伺服器當機、重新開機或者網絡故障導緻不存在過半的伺服器 與 Leader 伺服器保持正常通信時,所有程序(伺服器)進入崩潰恢複模式,首先選舉産生新的 Leader伺服器,然後叢集中 Follower 伺服器開始與新的 Leader 伺服器進行資料同步,當叢集中超過半數機器與該 Leader伺服器完成資料同步之後,退出恢複模式進入消息廣播模式,Leader 伺服器開始接收用戶端的事務請求生成事物提案來進行事務請求處理。
5. 四種類型的資料節點 Znode
(1)PERSISTENT-持久節點
除非手動删除,否則節點一直存在于 Zookeeper 上
(2)EPHEMERAL-臨時節點
臨時節點的生命周期與用戶端會話綁定,一旦用戶端會話失效(用戶端與zookeeper 連接配接斷開不一定會話失效),那麼這個用戶端建立的所有臨時節點都會被移除。
(3)PERSISTENT\_SEQUENTIAL-持久順序節點
基本特性同持久節點,隻是增加了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。
(4)EPHEMERAL\_SEQUENTIAL-臨時順序節點
基本特性同臨時節點,增加了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。
6. Zookeeper Watcher 機制 -- 資料變更通知
Zookeeper 允許用戶端向服務端的某個 Znode 注冊一個 Watcher 監聽,當服務端的一些指定事件觸發了這個 Watcher,服務端會向指定用戶端發送一個事件通知來實作分布式的通知功能,然後用戶端根據Watcher 通知狀态和事件類型做出業務上的改變。
工作機制:
(1)用戶端注冊 watcher
(2)服務端處理 watcher
(3)用戶端回調 watcher
Watcher 特性總結:
(1)一次性無論是服務端還是用戶端,一旦一個 Watcher 被 觸 發 ,Zookeeper 都會将其從相應的存儲中移除。這樣的設計有效的減輕了服務端的壓力,不然對于更新非常頻繁的節點,服務端會不斷的向用戶端發送事件通知,無論對于網絡還是服務端的壓力都非常大。
Java中間件真題解析位址:
Java中間件答案解析筆記(2)用戶端串行執行
用戶端 Watcher 回調的過程是一個串行同步的過程。
(3)輕量
3.1、Watcher 通知非常簡單,隻會告訴用戶端發生了事件,而不會說明事件的具體内容。
3.2、用戶端向服務端注冊 Watcher 的時候,并不會把用戶端真實的 Watcher 對象實體傳遞到服務端,僅僅是在用戶端請求中使用 boolean 類型屬性進行了标記。
(4)watcher event 異步發送 watcher 的通知事件從 server 發送到 client 是異步的,這就存在一個問題,不同的用戶端和伺服器之間通過 socket 進行通信,由于網絡延遲或其他因素導緻用戶端在不通的時刻監聽到事件,由于 Zookeeper 本身提供了 ordering guarantee,即用戶端監聽事件後,才會感覺它所監視 znode發生了變化。是以我們使用 Zookeeper 不能期望能夠監控到節點每次的變化。Zookeeper 隻能保證最終的一緻性,而無法保證強一緻性。
(5)注冊 watcher getData、exists、getChildren
(6)觸發 watcher create、delete、setData
(7)當一個用戶端連接配接到一個新的伺服器上時,watch 将會被以任意會話事件觸發。當與一個伺服器失去連接配接的時候,是無法接收到 watch 的。而當 client 重新連接配接時,如果需要的話,所有先前注冊過的 watch,都會被重新注冊。通常這是完全透明的。隻有在一個特殊情況下,watch 可能會丢失:對于一個未建立的 znode的 exist watch,如果在用戶端斷開連接配接期間被建立了,并且随後在用戶端連接配接上之前又删除了,這種情況下,這個 watch 事件可能會被丢失。
7. 用戶端注冊 Watcher 實作
(1)調用 getData()/getChildren()/exist()三個 API,傳入 Watcher 對象
(2)标記請求 request,封裝 Watcher 到 WatchRegistration
(3)封裝成 Packet 對象,發服務端發送 request
(4)收到服務端響應後,将 Watcher 注冊到 ZKWatcherManager 中進行管理
(5)請求傳回,完成注冊。
8. 服務端處理 Watcher 實作
9. 用戶端回調 Watcher
- 用戶端 SendThread 線程接收事件通知,交由 EventThread 線程回調 Watcher。
- 用戶端的 Watcher 機制同樣是一次性的,一旦被觸發後,該 Watcher 就失效了。
10. ACL 權限控制機制
11. Chroot 特性
12. 會話管理
13. 伺服器角色
14. Zookeeper 下 Server 工作狀态
伺服器具有四種狀态,分别是 LOOKING、FOLLOWING、LEADING、OBSERVING。
(1)LOOKING:尋 找 Leader 狀态。當伺服器處于該狀态時,它會認為目前叢集中沒有 Leader,是以需要進入 Leader 選舉狀态。
(2)FOLLOWING:跟随者狀态。表明目前伺服器角色是 Follower。
(3)LEADING:上司者狀态。表明目前伺服器角色是 Leader。
(4)OBSERVING:觀察者狀态。表明目前伺服器角色是 Observer。
15. 資料同步
16. zookeeper 是如何保證事務的順序一緻性的?
17. 分布式叢集中為什麼會有 Master?
在分布式環境中,有些業務邏輯隻需要叢集中的某一台機器進行執行,其他的機器可以共享這個結果,這樣可以大大減少重複計算,提高性能,于是就需要進行leader 選舉。
18. zk 節點當機如何處理?
19. zookeeper 負載均衡和 nginx 負載均衡差別
zk 的負載均衡是可以調控,nginx 隻是能調權重,其他需要可控的都需要自己寫插件;但是 nginx 的吞吐量比 zk 大很多,應該說按業務選擇用哪種方式。
20. Zookeeper 有哪幾種幾種部署模式?
部署模式:單機模式、僞叢集模式、叢集模式
21. 叢集最少要幾台機器,叢集規則是怎樣的?
叢集規則為 2N+1 台,N>0,即 3 台
22. 叢集支援動态添加機器嗎?
23. Zookeeper 對節點的 watch 監聽通知是永久的嗎?為什麼不是永久的?
24. Zookeeper 的 java 用戶端都有哪些?
java 用戶端:zk 自帶的 zkclient 及 Apache 開源的 Curator。
25. chubby 是什麼,和 zookeeper 比你怎麼看?
chubby 是 google 的,完全實作 paxos 算法,不開源。zookeeper 是 chubby的開源實作,使用 zab協定,paxos 算法的變種。
26. 說幾個 zookeeper 常用的指令。
常用指令:ls get set create delete 等。
27. ZAB 和 Paxos 算法的聯系與差別?
28. Zookeeper 的典型應用場景
Zookeeper 是一個典型的釋出/訂閱模式的分布式資料管理與協調架構,開發人員可以使用它來進行分布式資料的釋出和訂閱。
通過對 Zookeeper 中豐富的資料節點進行交叉使用,配合 Watcher 事件通知機制,可以非常友善的建構一系列分布式應用中年都會涉及的核心功能,如:
- (1)資料釋出/訂閱
- (2)負載均衡
- (3)命名服務
- (4)分布式協調/通知
- (5)叢集管理(6)Master 選舉
- (7)分布式鎖
- (8)分布式隊列
資料釋出/訂閱
介紹
資料釋出/訂閱系統,即所謂的配置中心,顧名思義就是釋出者釋出資料供訂閱者進行資料訂閱。
目的
動态擷取資料(配置資訊)
實作資料(配置資訊)的集中式管理和資料的動态更新
設計模式
Push 模式
Pull 模式
資料(配置資訊)特性
(1)資料量通常比較小
(2)資料内容在運作時會發生動态更新
(3)叢集中各機器共享,配置一緻
如:機器清單資訊、運作時開關配置、資料庫配置資訊等
基于 Zookeeper 的實作方式
· 資料存儲:将資料(配置資訊)存儲到 Zookeeper 上的一個資料節點
· 資料擷取:應用在啟動初始化節點從 Zookeeper 資料節點讀取資料,并在該節點上注冊一個資料變更
Watcher
· 資料變更:當變更資料時,更新 Zookeeper 對應節點資料,Zookeeper會将資料變更通知發到各客戶
端,用戶端接到通知後重新讀取變更後的資料即可。
負載均衡
zk 的命名服務
命名服務是指通過指定的名字來擷取資源或者服務的位址,利用 zk 建立一個全局的路徑,這個路徑就可以作為一個名字,指向叢集中的叢集,提供的服務的位址,或者一個遠端的對象等等。
分布式通知和協調
對于系統排程來說:操作人員發送通知實際是通過控制台改變某個節點的狀态,然後 zk 将這些變化發送給注冊了這個節點的 watcher 的所有用戶端。對于執行情況彙報:每個工作程序都在某個目錄下建立一個臨時節點。并攜帶工作的進度資料,這樣彙總的程序可以監控目錄子節點的變化獲得工作進度的實時的全局情況。
zk 的命名服務(檔案系統)
命名服務是指通過指定的名字來擷取資源或者服務的位址,利用 zk 建立一個全局的路徑,即是唯一的路徑,這個路徑就可以作為一個名字,指向叢集中的叢集,提供的服務的位址,或者一個遠端的對象等等。
zk 的配置管理(檔案系統、通知機制)程式分布式的部署在不同的機器上,将程式的配置資訊放在 zk 的 znode 下,當有配置發生改變時,也
就是 znode 發生變化時,可以通過改變 zk 中某個目錄節點的内容,利用 watcher 通知給各個用戶端,進而更改配置。
Zookeeper 叢集管理(檔案系統、通知機制)
所謂叢集管理無在乎兩點:是否有機器退出和加入、選舉 master。對于第一點,所有機器約定在父目錄下建立臨時目錄節點,然後監聽父目錄節點的子節點變化消息。一旦有機器挂掉,該機器與 zookeeper 的連接配接斷開,其所建立的臨時目錄節點被删除,所有其他機器都收到通知:某個兄弟目錄被删除,于是,所有人都知道:它上船了。新機器加入也是類似,所有機器收到通知:新兄弟目錄加入,highcount 又有了,對于第二點,我們稍微改變一下,所有機器建立臨時順序編号目錄節點,每次選取編号最小的機器作為 master 就好。
Zookeeper 分布式鎖(檔案系統、通知機制)
有了 zookeeper 的一緻性檔案系統,鎖的問題變得容易。鎖服務可以分為兩類,一個是保持獨占,另一個是控制時序。對于第一類,我們将 zookeeper 上的一個 znode 看作是一把鎖,通過 createznode的方式來實作。所
有用戶端都去建立 /distribute\_lock 節點,最終成功建立的那個用戶端也即擁有了這把鎖。用完删除掉自己建立的 distribute\_lock 節點就釋放出鎖。對于第二類, /distribute\_lock 已經預先存在,所有用戶端在它下面建立臨時順序編号目錄節點,和選master 一樣,編号最小的獲得鎖,用完删除,依次友善。Zookeeper 隊列管理(檔案系統、通知機制)
兩種類型的隊列:
(1)同步隊列,當一個隊列的成員都聚齊時,這個隊列才可用,否則一直等待所有成員到達。
(2)隊列按照 FIFO 方式進行入隊和出隊操作。
第一類,在約定目錄下建立臨時目錄節點,監聽節點數目是否是我們要求的數目。
第二類,和分布式鎖服務中的控制時序場景基本原理一緻,入列有編号,出列按編号。在特定的目錄下
建立 PERSISTENT\_SEQUENTIAL 節點,建立成功時Watcher 通知等待的隊列,隊列删除序列号最小的節點用以消費。此場景下Zookeeper 的 znode 用于消息存儲,znode 存儲的資料就是消息隊列中的消息内容,SEQUENTIAL 序列号就是消息的編号,按序取出即可。由于建立的節點是持久化的,是以不必擔心隊列消息的丢失問題。
RabbitMQ
1. 什麼是MQ
MQ就是消息隊列。是軟體和軟體進行通信的中間件産品
2. MQ的優點
- 異步處理 - 相比于傳統的串行、并行方式,提高了系統吞吐量。
- 應用解耦 - 系統間通過消息通信,不用關心其他系統的處理。
- 流量削鋒 - 可以通過消息隊列長度控制請求量;可以緩解短時間内的高并發請求。
- 日志處理 - 解決大量日志傳輸。
- 消息通訊 - 消息隊列一般都内置了高效的通信機制,是以也可以用在純的消息通訊。比如實
- 現點對點消息隊列,或者聊天室等。
3. 解耦、異步、削峰是什麼?。
- 解耦:A 系統發送資料到 BCD 三個系統,通過接口調用發送。如果 E 系統也要這個資料呢?那如果 C 系統現在不需要了呢?A 系統負責人幾乎崩潰…A 系統跟其它各種亂七八糟的系統嚴重耦合,A 系統産生一條比較關鍵的資料,很多系統都需要 A 系統将這個資料發送過來。如果使用 MQ,A系統産生一條資料,發送到 MQ 裡面去,哪個系統需要資料自己去 MQ 裡面消費。如果新系統需 要資料,直接從 MQ 裡消費即可;如果某個系統不需要這條資料了,就取消對 MQ 消息的消費即可。這樣下來,A 系統壓根兒不需要去考慮要給誰發送資料,不需要維護這個代碼,也不需要考慮 人家是否調用成功、失敗逾時等情況。就是一個系統或者一個子產品,調用了多個系統或者子產品,互相之間的調用很複雜,維護起來很麻煩。但是其實這個調用是不需要直接同步調用接口的,如果用 MQ 給它異步化解耦。
- 異步:A 系統接收一個請求,需要在自己本地寫庫,還需要在 BCD 三個系統寫庫,自己本地寫庫 要 3ms,BCD 三個系統分别寫庫要 300ms、450ms、200ms。最終請求總延時是 3 + 300 + 450 + 200 = 953ms,接近 1s,使用者感覺搞個什麼東西,慢死了慢死了。使用者通過浏覽器發起請求。 如果使用 MQ,那麼 A 系統連續發送 3 條消息到 MQ 隊列中,假如耗時 5ms,A 系統從接受一個 請求到傳回響應給使用者,總時長是 3 + 5 = 8ms。
- 削峰:減少高峰時期對伺服器壓力
4. 消息隊列有什麼缺點
5. 你們公司生産環境用的是什麼消息中間件?
- 這個首先你可以說下你們公司選用的是什麼消息中間件,比如用的是RabbitMQ,然後可以初步給一些你對不同MQ中間件技術的選型分析。
- 舉個例子:比如說ActiveMQ是老牌的消息中間件,國内很多公司過去運用的還是非常廣泛的,功能很強大。
- 但是問題在于沒法确認ActiveMQ可以支撐網際網路公司的高并發、高負載以及高吞吐的複雜場景,在國内網際網路公司落地較少。而且使用較多的是一些傳統企業,用ActiveMQ做異步調用和系統解耦。
- 然後你可以說說RabbitMQ,他的好處在于可以支撐高并發、高吞吐、性能很高,同時有非常完善便捷的背景管理界面可以使用。
- 另外,他還支援叢集化、高可用部署架構、消息高可靠支援,功能較為完善。
- 而且經過調研,國内各大網際網路公司落地大規模RabbitMQ叢集支撐自身業務的case較多,國内各種中小型網際網路公司使用RabbitMQ的實踐也比較多。
- 除此之外,RabbitMQ的開源社群很活躍,較高頻率的疊代版本,來修複發現的bug以及進行各種優化,是以綜合考慮過後,公司采取了RabbitMQ。
- 但是RabbitMQ也有一點缺陷,就是他自身是基于erlang語言開發的,是以導緻較為難以分析裡面的源碼,也較難進行深層次的源碼定制和改造,畢竟需要較為紮實的erlang語言功底才可以。
- 然後可以聊聊RocketMQ,是阿裡開源的,經過阿裡的生産環境的超高并發、高吞吐的考驗,性能卓越,同時還支援分布式事務等特殊場景。
- 而且RocketMQ是基于Java語言開發的,适合深入閱讀源碼,有需要可以站在源碼層面解決線上生産問題,包括源碼的二次開發和改造。
- 另外就是Kafka。Kafka提供的消息中間件的功能明顯較少一些,相對上述幾款MQ中間件要少很多。
- 但是Kafka的優勢在于專為超高吞吐量的實時日志采集、實時資料同步、實時資料計算等場景來設計。
- 是以Kafka在大資料領域中配合實時計算技術(比如Spark Streaming、Storm、Flink)使用的較多。但是在傳統的MQ中間件使用場景中較少采用。
6. Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什麼優缺點?
7. MQ 有哪些常見問題?如何解決這些問題?
8. 什麼是RabbitMQ?
RabbitMQ是一款開源的,Erlang編寫的,消息中間件; 最大的特點就是消費并不需要確定提供方 存在,實作了服務之間的高度解耦 可以用它來:解耦、異步、削峰。
9. rabbitmq 的使用場景
(1)服務間異步通信
(2)順序消費
(3)定時任務
(4)請求削峰
10. RabbitMQ基本概念
11. RabbitMQ的工作模式
12. 如何保證RabbitMQ消息的順序性?
- 拆分多個 queue(消息隊列),每個 queue(消息隊列) 一個 consumer(消費者),就是多一些 queue(消息隊列)而已,确實是麻煩點;
- 或者就一個 queue (消息隊列)但是對應一個 consumer(消費者),然後這個 consumer(消費者)内部用記憶體隊列做排隊,然後分發給底層不同的 worker 來處理。
13. 消息如何分發?
- 若該隊列至少有一個消費者訂閱,消息将以循環(round-robin)的方式發送給消費者。每條消息隻會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息并進行确認)。通過路由可實作多消費的功能
14. 消息怎麼路由?
15. 消息基于什麼傳輸?
16. 如何保證消息不被重複消費?或者說,如何保證消息消費時的幂等性?
17. 如何確定消息正确地發送至 RabbitMQ? 如何確定消息接收方消費了消息?
18. 如何保證RabbitMQ消息的可靠傳輸?
19. 為什麼不應該對所有的 message 都使用持久化機制?
20. 如何保證高可用的?RabbitMQ 的叢集
21. 如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以後該怎麼處理?有幾百萬消息持續積壓幾小時,怎麼辦?
22. 設計MQ思路
23.RoctetMq的架構
- NameServer
- Broker
- Producer
- Producer的負載均衡
- 發送的三種政策
- Consumer
- 推拉消費模式
- 叢集還是廣播
- Consumer的負載均衡
-Java中間件真題解析位址:
24. RocketMq消息模型(專業術語)
- Message
- Topic
- Tag
- Group
- Message Queue
- offset
25.核心問題
- 順序消息
- 消息過濾
- 消息去重
- 分布式事務消息
- 消息的可用性
- 刷盤實作
- 負載均衡