01 Kafka訂閱模式(Kafka數據消費)

时间:2024-06-01 13:09:58 编辑: 来源:

從發布-訂閱模式到消息隊列

發布-訂閱模式又稱為觀察者模式(網上也有很多說這兩種模式區別,個人覺得區別不大),在發布-訂閱模式中,主要是兩大塊。就是發布和訂閱,那么發布(publish)和訂閱(subscribe)之前的關聯點就是主題(topic).

舉個生活的例子,午餐定外賣,燕姐(broker)在外賣群里發布了兩個可以點的餐館,都城和輝記(這個可以稱為主題),小明(Consumer)點了輝記的,文哥(Consumer)點了都城的(這個可以稱為訂閱),都城餐館(procer)和輝記餐館(procer)做好了飯菜就回給外賣小哥送過來(消息協議),飯菜到了燕姐那里之后,那么小明和文哥就能去燕姐那里去拿(pull),也可以燕姐送過來(push)。這就是我們生活中最常見的發布-訂閱模式。

從上文中可以得到,外賣群是一個載體(MQ),承載消息的存儲和傳送,從這里可以引出消息隊列的這個概念,下面,繼續說下消息隊列。

MQ (Message Queue) 又稱消息隊列. 隊列我們都知道,那什么是消息呢?消息指的是同一臺機器的進程之間,或不同機器之間傳輸的數據。最簡單的說,我們一個Rpc 請求,所帶的數據就是一個消息。這就是傳統的通信模式。但是這種模式有很多缺陷,例如當網絡不好的時候,這種調用可能會丟失。

隊列提供了一種一步通信協議,這意味著消息的發送者和接收者不需要同時于消息保持聯系,發送者的消息會存儲在隊列中,直到接收者拿到它。 一般我們把消息的發送者稱為生產者,消息的接收者稱為消費者。由于生產者和消費者之間是不透明的,他們靠中間的紐帶-隊列來聯系,那么在隊列中,是消費者占主動還是生產者占主動呢,其實根據不同的獲取消息的方式可以分為 pull or push 著兩種。按字面上的理解,就是pull 是消費者需要自己控制去隊列拉取消息,而push則是生產者占主動位置,將產生的消息push 給消費者,而這種push 可以點對點,也可以是一對多,而這種一對多的模式就是我們常說的廣播模式

在分布式系統中,消息中間件是非常重要的組件,主要解決應用耦合,異步消息,流量削峰等問題。

常用的消息隊列中間件有 activeMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ

(可參考 買粉絲s://mp.weixin.qq.買粉絲/s/ad7jibTb5nTzh3nDQYKFeg ? 覺得這篇文章寫得很不錯也很詳細)

這次我主要寫的是kafka 這個消息中間件,kafka 是采用pull 這種模式來消費信息的,生產者將消息放入隊列中,而消費者可以通過epull 方法獲取消息來消費,下面還是先說下kafka 的幾個關鍵概念吧

Kafka是最初由Linkedin公司開發,是一個分布式、分區的、多副本的、多訂閱者,基于zookeeper協調的分布式日志系統(也可以當做MQ系統),常見可以用于web/nginx日志、訪問日志,消息服務等等,Linkedin于2010年貢獻給了Apache基金會并成為頂級開源項目

主要應用場景是:日志收集系統和消息系統。

Kafka主要設計目標如下:

同時支持離線數據處理和實時數據處理。

一個典型的kafka集群中包含若干procer,若干broker,若干買粉絲nsumer,以及一個Zookeeper集群。Kafka通過Zookeeper管理集群配置,選舉leader,以及在買粉絲nsumer group發生變化時進行rebalance。procer使用push模式將消息發布到broker,買粉絲nsumer使用pull模式從broker訂閱并消費消息。

Topic & Partition

一個topic可以認為一個一類消息,每個topic將被分成多個partition,每個partition在存儲層面是append log文件。

在Kafka文件存儲中,同一個topic下有多個不同partition,每個partition為一個目錄,partiton命名規則為topic名稱+有序序號,第一個partiton序號從0開始,序號最大值為partitions數量減1

每個partion(目錄)相當于一個巨型文件被平均分配到多個大小相等segment(段)數據文件中。但每個段segment file消息數量不一定相等,這種特性方便old segment file快速被刪除。

每個partiton只需要支持順序讀寫就行了,segment文件生命周期由服務端配置參數決定。

這樣做的好處就是能快速刪除無用文件,有效提高磁盤利用率。

segment file組成:由2大部分組成,分別為index file和data file,此2個文件一一對應,成對出現,后綴".index"和“.log”分別表示為segment索引文件、數據文件.

segment文件命名規則:partion全局的第一個segment從0開始,后續每個segment文件名為上一個segment文件最后一條消息的offset值。數值最大為64位long大小,19位數字字符長度,沒有數字用0填充。

同一Topic的一條消息只能被同一個Consumer Group內的一個Consumer消費,但多個Consumer Group可同時消費這一消息。

這是Kafka用來實現一個Topic消息的廣播(發給所有的Consumer)和單播(發給某一個Consumer)的手段。一個Topic可以對應多個Consumer Group。如果需要實現廣播,只要每個Consumer有一個獨立的Group就可以了。要實現單播只要所有的Consumer在同一個Group里。用Consumer Group還可以將Consumer進行自由的分組而不需要多次發送消息到不同的Topic。

參考:

買粉絲://買粉絲.linkedkeeper.買粉絲/detail/blog.action?bid=1016&hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

Kafka數據消費

消費者負責從訂閱的主題上拉取消息,消費組是邏輯概念。一個消費者只屬于一個消費組,一個消費組包一個或多個消費者。當消息發布到主題后,會被投遞到每個消費組,但每個消費組中只有一個消費者能消費給消息。

消費者如何知道該消費哪個分區?當消費組內消費者個數發生變化時,分區分配是如何變化的呢?

按照消費者總數和分區總數進行整除運算來獲得一個跨度,然后將分區按照跨度進行平均分配, 以保證分區盡可能均勻地分配給所有的消費者。對于 每一個主題 該策略會將消費組內所有的消費者按照名稱的字典序排序然后為每個消費者劃分固定的分區范圍,如果不夠平均分配,那么字典序靠前的消費者會被多分配一個分區。

假設n=分區數/消費者數量,m=分區數%消費者數量,那么前m個消費者每個分配n+1分區,后面的每個消費者分配n個分區。

如圖所示主題中共有7個分區,此時消費組內只有一個消費者C0,C0訂閱7個分區。

隨著消費組內消費者不斷加入,分區逐漸從C0分配到C1~C6,當最后一個消費者C7加入后,此時總共有8個消費者但是只有7個分區,因此C7由于分配不到分區而無法消費任何消息。

消費者并非越多越好,消費者數量應小于等于分區數量,否則會造成資源的浪費

缺點:

當一個消費組訂閱兩個分別包含四個分區的主題時,分區分配結果如下,比較均勻。

但當兩個主題各有3個分區時,則會出現如下分區不均的問題。類似情況擴大的話,可能出現消費者過載問題。

將消費組內所有消費者及消費者訂閱的所有主題的分區按照字典序排序,然后通過輪詢方式將分區依次分配給每個消費者。如果消費組內消費者的訂閱信息都是相同的,那么分區分配會比較均勻。如一個消費組兩個消費者,分別訂閱兩個都有3的分區的主題,如圖。

但是當消費組內消費者的訂閱信息不同時,則會出現分配不均問題。如圖,假設消費組內有三個消費者,主題1/2/3分別有1/2/3個分區,C0訂閱主題1,C1訂閱主題1和2,C2訂閱主題1/2/3,分區結果將會如下圖所示。

后來引入的策略,主要目的:

假設三個消費者,訂閱了4個主題,每個主題有兩個分區,那么初始分區分配結果如下:

乍一看,跟RoundRobin分配策略結果相同,但此時如果C1下線,那么消費組會執行再均衡操作,重新分配消息分區。如果是RoundRobin策略,分配結果如下:

而如果是Sticky分配策略,則結果如下:

StickyAssignor保留了上一次對C0和C2的分配結果,將C1的分區分配給C0和C2使其均衡。

如果發生分區重分配,那么對于同一個分區而 ,有可能之前的消費者和新指派的消費者不是同一個,之前消費者進行到一半的處理還要在新指派的消費者中再次復現一遍,造成重復消費。StickyAssignor分配策略如同其名稱中的"sticky"一 樣,讓分配策略具備的“黏性”,盡可能地讓前后兩次分配相同,進而減少系統資源的損耗及其他異常情況的發生。

再來看下,消費者訂閱信息不相同的情況,拿RoundRobinAssignor中的實例來說。

假設消費組內有三個消費者,主題1/2/3分別有1/2/3個分區,C0訂閱主題1,C1訂閱主題1和2,C2訂閱主題1/2/3,RoundRobinAssignor分區結果將會如下圖所示。

而采用StickyAssignor時,分區分配結果如下:

搜索关键词: