成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

快到起飛的Kafka,是如何設計的?

開發 架構 開發工具 Kafka
消息隊列是分布式系統中重要的組件,在很多生產環境如商品搶購等需要控制并發量的場景下都需要用到。

[[409438]]

圖片來自包圖網

消息隊列主要解決了應用耦合、異步處理、流量削鋒等問題,當前使用較多的消息隊列有 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ 等。

而部分數據庫如 Redis,MySQL 以及 phxsql 也可實現消息隊列的功能。

消息隊列在實際應用場景:

  • 應用解耦:多應用間通過消息隊列對同一消息進行處理,避免調用接口失敗導致整個過程失敗。
  • 異步處理:多應用對消息隊列中同一消息進行處理,應用間并發處理消息,相比串行處理,減少處理時間。
  • 限流削峰:廣泛應用于秒殺或搶購活動中,避免流量過大導致應用系統掛掉的情況。

今天分享一篇經典的 Kafka 設計剖析文章給大家,Kafka 作為頂級消息中間件,據 Confluent 稱,超過三分之一的財富 500 強公司使用 Apache Kafka。

Kafka 的性能快,吞吐量大,并且高于其他消息隊列一個水平,即使在消息量巨大的情況下還能保持高性能,在互聯網公司中非常流行,希望大家領悟到 Kafka 設計的核心原理。

Kafka 架構

Kafka 是一個被精心設計的東西,我只能這樣說。我這里所謂的精心不是說它很完備的實現了某種規范。

像個學生那般完成了某個作業,比如 JMS,恰恰相反,Kafka 突破了類似 JMS 這種規范性的束縛,它是卓越的,乃 yet another JMS。

當我用 yet…如此稱呼一個技術的時候,意味著這玩意兒已經進入了我的視野。好了,現在是 Kafka 和 Storm 時間,本文先談 Kafka。

Kafka 是什么?

參見官方文檔,它是 Apache 的一個項目。它是一個消息隊列。

消息隊列若何:消息隊列是生產者和消費者之間的信使,避免了二者之間直接的接觸。

在效果上,它可能和緩存所起的作用一樣,平滑了生產者和消費者之間的代謝速率差,但是在其根本目的上,它是為了解除生產者和消費者之間的耦合。如果你覺得有點費解,那么簡單點說。

fire and forget,這句話的意思再簡單點說,就是真男人從不看爆炸,煙頭往油箱里一丟,把風衣的領子一豎,手插褲兜里,徑直走開,決不不回頭。

消息隊列,以下簡稱 MQ,就是造就這種真男人的。它能讓生產者把消息扔進 MQ 就不管了,然后消費者從 MQ 里取消息即可,不用和生產者交互。

下面的篇幅,我將逐步用我的方式演化出 Kafka 的原型,為了掌握整體脈絡,難免會隱掉很多細節。

當然這些細節可以隨便在其官方文檔以及別人的博客里搜到,我的目的只是希望能整理出一個脈絡,在設計類似的系統的時候,見招拆招以備參考。

MQ 朝著“正確”方向的演化

Kafka 就一定正確嗎?客觀講,肯定不,但是它是本文的主角,所以它就一定正確。

我們先來看看作為通用的 MQ,其最簡單的形式,一般而言,這是大家在首次接觸到 MQ 后的一個課后作業。

現在有個問題,如果有兩個或者多個消費者需要消費消息,怎么辦?很簡單,廣播唄:

消費者是上帝,很難搞的,你推給它們的東西,并不是它們全部都想要的,只要一部分怎么辦?

好吧,消費者一定在怪 MQ 服務不周,然而 MQ 有什么錯,它又不理解消息的語義,面對百般刁難的消費者,它最多只能要求生產者把消息細分一下,因此就出現了多個 Topic:

這是很顯然的想法,就是是在消息入隊處區分消息的 Topic,然消費者從取自己感興趣的消息隊列取消息即可。

但還是會潛在的多個消費對同一 Topic 消息感興趣的情況:

如果采用廣播,那么就仍然會出現冗余傳播問題,如果單播,那么一個消費者取出消息后,這條消息該不該刪除呢?如果刪除了,另一個消費者怎么辦?廣播會浪費帶寬,不廣播也不行…

這貌似進入了一個死循環,必須一勞永逸地從根源解決問題才行。顯然的想法是下面的方案(至少我自己設計的話就會這么做):

問題是解決了,然而我的天啊,仔細想一下先前的架構,把簡圖畫出來后,會發現事情會一發而不可收拾,MQ 本身的邏輯太復雜了:

回到 UNIX 哲學,遇到新問題的時候,要新編一個程序,而不是為已有的程序添加一個功能。

本著這個思路,為什么不把這件因為消費者而導致復雜化的事情完全交給消費者呢?

有點往 Kafka 上靠了啊。如果把 MQ 里面的數據全部持久化存儲,消費者不就可以各取所需了嗎?

這是一個根本的轉變,如果以前的方式是限量商務套餐-套餐強行推給你,不想要的自己扔掉,那么現在的方式就是無限量自助餐-想要什么自己去拿即可。

消息自取,消息永遠都在 MQ,消費者隨便取,取哪個消息都行,什么時候取都行。

消費者只需要告訴 MQ 它想要哪個消息就好,因此需要傳遞一個消息的 offset 參數:

然而自助餐也有打烊的時候,部分也會限制就餐時長,這是 Kafka 策略化存儲的問題,詳見文檔。

簡化一下,現在看下圖:

一切 OK 了。嗯,是的,這就是 Kafka 的原始模型。然而 Kafka 遠不僅此而已。且看下文繼續演化。

集群化,容錯

先看一下現在的情況:

這是在邏輯上一個 Kafka 類似的 MQ 應有的結構。但是在物理實現上,它又如何呢?

常聽人說,Kafka 一開始就是為分布式而生的,這話怎么理解呢?我們只需要先理解它如何擴容,然后再理解它如何將擴容作用于不同的機器即可。先看擴容。

類似高速公路,一般當你聽到廣深高速的時候,我們知道這是從廣州到深圳的一條高速公路,這是邏輯上的說法,類似到目前為止我們討論的 MQ 的 Topic。

然而這條高速公路到底長什么樣子,沿途怎么路由,這就是物理實現了。此外,所有的道路都會分多個車道用于并行。

嚴格來講,每一個車道都會被細分,比如小型車道,客車道,大貨車道,超車道等等,所有這些車道上的車都是到達同一個目的地(屬于同一個 Topic),然而它們確實是細分的不同種類。

把一個叫做 partition 的概念類比為車道,如下圖:

注意這個 key hash 模塊,這里就是區分車子要進入哪個車道的邏輯。在 Kafka 的術語中,車道就是 partition,即分區。

在同一個 Topic 中分發消息的時候,你要自己設計 hash 函數,該 hash 函數就是一個分發策略,決定把消息按序放到哪一個分區中去。

溫州皮鞋廠老板說類比和舉例不好,但這是技術散文,不是技術文檔,多半是給自己看,所以還要類比。

Topic Routing 做的事是決定從哪條高速公路到哪里,而 key hash 則是決定你是坐轎車,客車還是卡車過去。

值得注意的是,Kafka 只保證同一 Topic 內同一 partition 內消息的有序性,無法做到全局有序性。

這并不是一個缺陷,這是兩全不能齊美的。完全的順序就需要串行化,然而串行化就無法并行,這簡直就是廢話!

現在,在 Topic 之下,我們又有了一個新的單位,叫做 partition,這個叫做 partition 的就是 Kafka 中最基本的部署單位,這一點務必要記住,它關乎到如何組織你的集群。

好了,看一下這些 Topic 以及其旗下的 partition 是如何部署在 M1 和 M2 兩臺機器上的吧:

以上是花開兩朵,各表一枝,現在該說說消費者了。

消費者面對 MQ 本身進化到如此細粒度,該如何應對呢?其實消費者也有橫向擴展的需求,如果說消費者對應 partition,那么對應 Topic 的就是消費者的上級了。

因此多加了一個層次,引出消費組的概念,解決問題:

從 CPU cache 到 Kafka,設計思路殊途同歸,這就是一個典型的全方位組相聯結構:

到此為止,全部圖景已經完全繪制完畢,是時候展示集群的部署了。我們知道所謂的 Kafka 集群,就是將各個 Topic 的 partition 部署在不同的機器上,達到兩個目的。

一個是負載均衡,即提供訪問的并行性,另一個就是提供高可用性,即做熱備份,這兩個功能我希望能用一個圖展示:

總體的一個結構如下:

持久化存儲/查詢機制

上面的兩個小節,我已經展示了 Kafka 是如何一步一步地肚子里面的勾當內外有別的,雖然我不知道作者怎么去設計,但如果是我自己,我肯定就是上面這個思路了…

前面的敘述終究是概覽,不甚過癮。本節將給出半點細節,瑾闡釋一下 Kafka 存儲的半景。

我們知道,Kafka 為了卸載 MQ 本身的復雜性,為了其真正無狀態的設計,它將狀態維護機制這口鍋完全甩給了消費者。

因此取消息的問題就轉化成了消費者拿著一個 offset 索引來 Kafka 存儲器里取消息的問題,這就涉及到了性能。But 如何能查的更快?How?

還是先給出一個最簡單的場景。假設 Kafka 的每一個 partition 都一個完整獨立的文件,那么如果這個文件非常大,事實上也確實非常大(有可能到達 T 級別甚至 P 級別…)。

那么在大文件中檢索一個特定的消息本身就是一個頭疼的問題,并且該文件還在磁盤中,這更是雪上加霜,我們都知道磁盤的隨機讀寫是硬傷,順序讀寫也好不到哪去,這怎么辦?

遍歷?如果每一個 partition 只是一個獨立文件,那么只能遍歷:

面對這個遍歷問題,一般的解決方案就是建立索引,并且把索引數據常駐內存,很多數據庫就是這么干的,Kafka 當然也可以這么干。

Kafka 比較帥的一點就是它并不借助任何特殊的文件系統,它的數據就存在一般的文件中。

然而它把一個 partition 分成了等大小的一系列小文件,因此在物理上,并不存在一個完整的 partition 文件,partiotion 只是表現為一個目錄。

我們知道,文件系統管理幾個等大的文件是非常方便的:

以上的例子中,一個 partiton 被分成了 100M 大小的文件,這種小文件叫做分段。

在 Kafka 存儲的時候,每一個段文件存滿為止再開辟下一個,由于消息的長度并不一定統一,因此每一個小段文件里面包含的消息數量并不一定一樣多。

但是不管怎樣,抽取每一個段文件的首尾消息偏移作為元數據保存起來是一件一勞永逸的事情,這便于建立一個常駐內存的索引:

通過這個區間查找樹,很快就能定位到特定的段文件,但是事情并沒有結束。

在 Kafka 中,每一個 partition 的段文件,均配帶一個 index 索引文件,這個文件是做什么的呢?它是段文件內部消息的稀疏索引,見下圖:

最終,經過兩次區間樹查找之后,最多再經歷一次簡單的遍歷即可完成 offset 定位工作。

誠然,最終的遍歷可能是少不了的,但是 Kafka 盡可能地避免了大長段耗時的遍歷計算,而是將遍歷壓縮到一個很小的量級,這是一個權衡!跟誰權衡呢?為什么不把段文件所有消息的索引均建立起來呢?

很簡單,建立全部的索引會造成索引非常大,這樣如果你還想其常駐內存的話,內存占用會很大,這確實又是一個時間和空間之間的權衡了。

稀疏索引閑談

稀疏索引很有用,除了本文列舉的 Kafka 的 segment index 稀疏索引之外,還有兩個更為常見的例子(我不是應用編程的,我是搞內核網絡協議棧的,所以在我看來 Kafka 更不常見)

索引整個內存地址空間,稀疏化的做法就是分頁,即采用規則的方式將內存劃分為等大小的塊,叫做內存頁,然后索引這些內存頁即可,頁表而不是地址表稀疏化索引,減小索引的大小。

另外,IP 地址具有地域聚集性,因此對于路由器物理設備而言,對于每一個接口引出的方向,其 IP 地址集在很大程度上是可以聚集的。

路由表一開始采用地址分類的方法,后來采用了前綴匹配的方法稀疏化索引,地址分類有點像內存地址分頁,只是頁面有多種大小而不僅僅是一種。

而這里的地址前綴則比較像 Kafka 使用的兩種索引,第一種是段索引,這是規則的,第二種是消息索引,這是不規則的。因為消息并不定長。

兩種說法總結如下:

OS 內存頁表:在從虛擬地址定位物理地址的時候,需要一一對應定位到每一個地址嗎?

假如真是這樣子,那么光頁表項這種管理內存就要耗多少你算過嗎?虛擬地址和物理地址將會是全相聯結構。

采用稀疏索引后,只需要定位一個 4K 大小的頁面即可,這將大大減小內存頁表的內存占用。從而更加高效。

路由表:將每一個 IP 地址均對應到路由器設備的接口嗎?這不現實。解決方案一開始是基于分配機構的分類地址稀疏索引,后來采用了基于使用結構的無類子網的前綴系數索引,無論哪種情況,均大大減少了路由表項的數量。

UNIX 哲學的出路

沒出路了!Why?因為只有復雜才能體現自己的工作量。

人們都希望制造門檻,把程序做的非常復雜,方才體現自己的能力,畢竟簡單的東西大家都會,想體現區別,只能讓自己的東西更復雜。

如果你用幾行 Bash 腳本完成了一項艱巨的工作,經理大概率會覺得你這是奇技淫巧,完全無法和 C++ 的方案相比。Python 好一點,Java 則更好。

4,5 年以前的曾經,我們有個編程道場的活動,有一次的一個題目是拼接字符串,即 join 操作,當時的經理兼主持者強調盡量用現成的接口,然而…

多少個優秀的極簡方案沒有被表揚,最后被表揚的方案你們知道其特征是什么嗎?其特征就是復雜。

我記得當時這個方案的作者上臺介紹他的方案,上來就說”我這個設計非常簡單…”結果呢,唉,用技術術語講,過度設計了,用白話講,裝逼了。主持者顯然也是完全半瓶子晃蕩的吧,哈哈。

事情必須做的盡量復雜,這樣才是能力的體現,2 行能搞定的東西,必須湊夠 30 行才算牛逼。UNIX 哲學,在我們這,顯然不合適吧。

作者:極客重生

編輯:陶家龍

出處:轉載自公眾號極客重生(ID:geek__coding)

 

責任編輯:武曉燕 來源: 極客重生
相關推薦

2022-01-05 16:16:02

查詢編程工程師

2024-02-23 08:18:32

首屏產品瀏覽器

2019-10-12 10:39:44

AR眼鏡Facebook蘋果

2022-11-07 09:25:02

Kafka存儲架構

2021-01-28 05:11:26

HDFS架構Hadoop

2019-12-16 09:37:19

Kafka架構數據

2019-12-11 10:14:23

Kafka吞吐量架構

2023-11-10 08:18:27

JavaGraalVM

2017-02-11 09:58:19

2020-05-25 08:05:11

KafkaActiveMQRabbitMQ

2019-04-04 14:51:57

banner廣告設計分析

2024-10-22 15:25:20

2022-06-01 07:49:43

索引數據Mysql

2019-04-01 13:53:43

2020-10-22 09:37:39

存儲Kafka設計

2018-12-25 09:44:42

2019-12-23 09:25:29

日志Kafka消息隊列

2012-08-03 09:09:59

網頁設計設計

2013-07-24 16:08:01

Android模擬器Genymotion

2022-04-19 20:51:20

軟件開發耦合代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲国产精品久久久久 | 亚洲少妇综合网 | 国产男女视频网站 | 国产精品国产三级国产aⅴ原创 | 欧美日韩视频在线播放 | 国产精品亚洲精品 | 在线成人| 精品久久久久久久久久久久久久久久久 | 亚洲福利 | 麻豆一区二区三区精品视频 | 国产小视频在线观看 | 2023亚洲天堂| 色资源在线 | 国产一区二区免费 | 国产精品theporn | 91精品久久久久久久久久小网站 | 综合色在线 | 国产精品一区在线 | av一区二区三区四区 | 亚洲视频一区在线观看 | 91成人 | 精品欧美乱码久久久久久1区2区 | 免费a网 | 91精品国产一区二区 | 人人九九精 | 欧美日韩中 | 91麻豆精品一区二区三区 | 九九伦理片 | 91精品国产色综合久久不卡98 | 成人高清视频在线观看 | 三级视频网站 | 国产欧美一区二区三区在线看 | 精品国产一区二区三区久久久四川 | 福利社午夜影院 | 一区二区三区视频在线 | 亚洲成色777777在线观看影院 | 天天色天天色 | 国产欧美精品 | 欧美激情在线精品一区二区三区 | 国产一区二区毛片 | 91精品国产欧美一区二区成人 |