<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>

          Kafka 為什么能那么快的 6 個(gè)原因

          共 6425字,需瀏覽 13分鐘

           ·

          2020-07-31 22:24

          點(diǎn)擊藍(lán)色“JavaKeeper”關(guān)注我喲
          加個(gè)“星標(biāo)”,一起成長(zhǎng),做牛逼閃閃的技術(shù)人

          無論 kafka 作為 MQ 也好,作為存儲(chǔ)層也罷,無非就是兩個(gè)功能(好簡(jiǎn)單的樣子),一是 Producer 生產(chǎn)的數(shù)據(jù)存到 broker,二是 Consumer 從 broker 讀取數(shù)據(jù)。那 Kafka 的快也就體現(xiàn)在讀寫兩個(gè)方面了,下面我們就聊聊 Kafka 快的原因。

          1. 利用 Partition 實(shí)現(xiàn)并行處理

          我們都知道 Kafka 是一個(gè) Pub-Sub 的消息系統(tǒng),無論是發(fā)布還是訂閱,都要指定 Topic。

          Topic 只是一個(gè)邏輯的概念。每個(gè) Topic 都包含一個(gè)或多個(gè) Partition,不同 Partition 可位于不同節(jié)點(diǎn)。

          一方面,由于不同 Partition 可位于不同機(jī)器,因此可以充分利用集群優(yōu)勢(shì),實(shí)現(xiàn)機(jī)器間的并行處理。另一方面,由于 Partition 在物理上對(duì)應(yīng)一個(gè)文件夾,即使多個(gè) Partition 位于同一個(gè)節(jié)點(diǎn),也可通過配置讓同一節(jié)點(diǎn)上的不同 Partition 置于不同的磁盤上,從而實(shí)現(xiàn)磁盤間的并行處理,充分發(fā)揮多磁盤的優(yōu)勢(shì)。

          能并行處理,速度肯定會(huì)有提升,多個(gè)工人肯定比一個(gè)工人干的快。

          可以并行寫入不同的磁盤?那磁盤讀寫的速度可以控制嗎?

          那就先簡(jiǎn)單扯扯磁盤/IO 的那些事

          硬盤性能的制約因素是什么?如何根據(jù)磁盤I/O特性來進(jìn)行系統(tǒng)設(shè)計(jì)?

          硬盤內(nèi)部主要部件為磁盤盤片、傳動(dòng)手臂、讀寫磁頭和主軸馬達(dá)。實(shí)際數(shù)據(jù)都是寫在盤片上,讀寫主要是通過傳動(dòng)手臂上的讀寫磁頭來完成。實(shí)際運(yùn)行時(shí),主軸讓磁盤盤片轉(zhuǎn)動(dòng),然后傳動(dòng)手臂可伸展讓讀取頭在盤片上進(jìn)行讀寫操作。磁盤物理結(jié)構(gòu)如下圖所示:

          由于單一盤片容量有限,一般硬盤都有兩張以上的盤片,每個(gè)盤片有兩面,都可記錄信息,所以一張盤片對(duì)應(yīng)著兩個(gè)磁頭。盤片被分為許多扇形的區(qū)域,每個(gè)區(qū)域叫一個(gè)扇區(qū)。盤片表面上以盤片中心為圓心,不同半徑的同心圓稱為磁道,不同盤片相同半徑的磁道所組成的圓柱稱為柱面。磁道與柱面都是表示不同半徑的圓,在許多場(chǎng)合,磁道和柱面可以互換使用。磁盤盤片垂直視角如下圖所示:

          圖片來源:commons.wikimedia.org

          影響磁盤的關(guān)鍵因素是磁盤服務(wù)時(shí)間,即磁盤完成一個(gè)I/O請(qǐng)求所花費(fèi)的時(shí)間,它由尋道時(shí)間、旋轉(zhuǎn)延遲和數(shù)據(jù)傳輸時(shí)間三部分構(gòu)成。

          機(jī)械硬盤的連續(xù)讀寫性能很好,但隨機(jī)讀寫性能很差,這主要是因?yàn)榇蓬^移動(dòng)到正確的磁道上需要時(shí)間,隨機(jī)讀寫時(shí),磁頭需要不停的移動(dòng),時(shí)間都浪費(fèi)在了磁頭尋址上,所以性能不高。衡量磁盤的重要主要指標(biāo)是IOPS和吞吐量。

          在許多的開源框架如 Kafka、HBase 中,都通過追加寫的方式來盡可能的將隨機(jī) I/O 轉(zhuǎn)換為順序 I/O,以此來降低尋址時(shí)間和旋轉(zhuǎn)延時(shí),從而最大限度的提高 IOPS。

          感興趣的同學(xué)可以看看 磁盤I/O那些事[1]

          磁盤讀寫的快慢取決于你怎么使用它,也就是順序讀寫或者隨機(jī)讀寫。

          2. 順序?qū)懘疟P

          圖片來源:kafka.apache.org

          Kafka 中每個(gè)分區(qū)是一個(gè)有序的,不可變的消息序列,新的消息不斷追加到 partition 的末尾,這個(gè)就是順序?qū)憽?/p>

          很久很久以前就有人做過基準(zhǔn)測(cè)試:《每秒寫入2百萬(在三臺(tái)廉價(jià)機(jī)器上)》http://ifeve.com/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines/

          由于磁盤有限,不可能保存所有數(shù)據(jù),實(shí)際上作為消息系統(tǒng) Kafka 也沒必要保存所有數(shù)據(jù),需要?jiǎng)h除舊的數(shù)據(jù)。又由于順序?qū)懭氲脑?,所?Kafka 采用各種刪除策略刪除數(shù)據(jù)的時(shí)候,并非通過使用“讀 - 寫”模式去修改文件,而是將 Partition 分為多個(gè) Segment,每個(gè) Segment 對(duì)應(yīng)一個(gè)物理文件,通過刪除整個(gè)文件的方式去刪除 Partition 內(nèi)的數(shù)據(jù)。這種方式清除舊數(shù)據(jù)的方式,也避免了對(duì)文件的隨機(jī)寫操作。

          3. 充分利用 Page Cache

          引入 Cache 層的目的是為了提高 Linux 操作系統(tǒng)對(duì)磁盤訪問的性能。Cache 層在內(nèi)存中緩存了磁盤上的部分?jǐn)?shù)據(jù)。當(dāng)數(shù)據(jù)的請(qǐng)求到達(dá)時(shí),如果在 Cache 中存在該數(shù)據(jù)且是最新的,則直接將數(shù)據(jù)傳遞給用戶程序,免除了對(duì)底層磁盤的操作,提高了性能。Cache 層也正是磁盤 IOPS 為什么能突破 200 的主要原因之一。

          在 Linux 的實(shí)現(xiàn)中,文件 Cache 分為兩個(gè)層面,一是 Page Cache,另一個(gè) Buffer Cache,每一個(gè) Page Cache 包含若干 Buffer Cache。Page Cache 主要用來作為文件系統(tǒng)上的文件數(shù)據(jù)的緩存來用,尤其是針對(duì)當(dāng)進(jìn)程對(duì)文件有 read/write 操作的時(shí)候。Buffer Cache 則主要是設(shè)計(jì)用來在系統(tǒng)對(duì)塊設(shè)備進(jìn)行讀寫的時(shí)候,對(duì)塊進(jìn)行數(shù)據(jù)緩存的系統(tǒng)來使用。

          使用 Page Cache 的好處:

          • I/O Scheduler 會(huì)將連續(xù)的小塊寫組裝成大塊的物理寫從而提高性能

          • I/O Scheduler 會(huì)嘗試將一些寫操作重新按順序排好,從而減少磁盤頭的移動(dòng)時(shí)間

          • 充分利用所有空閑內(nèi)存(非 JVM 內(nèi)存)。如果使用應(yīng)用層 Cache(即 JVM 堆內(nèi)存),會(huì)增加 GC 負(fù)擔(dān)

          • 讀操作可直接在 Page Cache 內(nèi)進(jìn)行。如果消費(fèi)和生產(chǎn)速度相當(dāng),甚至不需要通過物理磁盤(直接通過 Page Cache)交換數(shù)據(jù)

          • 如果進(jìn)程重啟,JVM 內(nèi)的 Cache 會(huì)失效,但 Page Cache 仍然可用

          Broker 收到數(shù)據(jù)后,寫磁盤時(shí)只是將數(shù)據(jù)寫入 Page Cache,并不保證數(shù)據(jù)一定完全寫入磁盤。從這一點(diǎn)看,可能會(huì)造成機(jī)器宕機(jī)時(shí),Page Cache 內(nèi)的數(shù)據(jù)未寫入磁盤從而造成數(shù)據(jù)丟失。但是這種丟失只發(fā)生在機(jī)器斷電等造成操作系統(tǒng)不工作的場(chǎng)景,而這種場(chǎng)景完全可以由 Kafka 層面的 Replication 機(jī)制去解決。如果為了保證這種情況下數(shù)據(jù)不丟失而強(qiáng)制將 Page Cache 中的數(shù)據(jù) Flush 到磁盤,反而會(huì)降低性能。也正因如此,Kafka 雖然提供了 flush.messagesflush.ms 兩個(gè)參數(shù)將 Page Cache 中的數(shù)據(jù)強(qiáng)制 Flush 到磁盤,但是 Kafka 并不建議使用。

          4. 零拷貝技術(shù)

          Kafka 中存在大量的網(wǎng)絡(luò)數(shù)據(jù)持久化到磁盤(Producer 到 Broker)和磁盤文件通過網(wǎng)絡(luò)發(fā)送(Broker 到 Consumer)的過程。這一過程的性能直接影響 Kafka 的整體吞吐量。

          操作系統(tǒng)的核心是內(nèi)核,獨(dú)立于普通的應(yīng)用程序,可以訪問受保護(hù)的內(nèi)存空間,也有訪問底層硬件設(shè)備的權(quán)限。

          為了避免用戶進(jìn)程直接操作內(nèi)核,保證內(nèi)核安全,操作系統(tǒng)將虛擬內(nèi)存劃分為兩部分,一部分是內(nèi)核空間(Kernel-space),一部分是用戶空間(User-space)。

          傳統(tǒng)的 Linux 系統(tǒng)中,標(biāo)準(zhǔn)的 I/O 接口(例如read,write)都是基于數(shù)據(jù)拷貝操作的,即 I/O 操作會(huì)導(dǎo)致數(shù)據(jù)在內(nèi)核地址空間的緩沖區(qū)和用戶地址空間的緩沖區(qū)之間進(jìn)行拷貝,所以標(biāo)準(zhǔn) I/O 也被稱作緩存 I/O。這樣做的好處是,如果所請(qǐng)求的數(shù)據(jù)已經(jīng)存放在內(nèi)核的高速緩沖存儲(chǔ)器中,那么就可以減少實(shí)際的 I/O 操作,但壞處就是數(shù)據(jù)拷貝的過程,會(huì)導(dǎo)致 CPU 開銷。

          我們把 Kafka 的生產(chǎn)和消費(fèi)簡(jiǎn)化成如下兩個(gè)過程來看[2]

          1. 網(wǎng)絡(luò)數(shù)據(jù)持久化到磁盤 (Producer 到 Broker)
          2. 磁盤文件通過網(wǎng)絡(luò)發(fā)送(Broker 到 Consumer)
          4.1 網(wǎng)絡(luò)數(shù)據(jù)持久化到磁盤 (Producer 到 Broker)

          傳統(tǒng)模式下,數(shù)據(jù)從網(wǎng)絡(luò)傳輸?shù)轿募枰?4 次數(shù)據(jù)拷貝、4 次上下文切換和兩次系統(tǒng)調(diào)用。

          data = socket.read()// 讀取網(wǎng)絡(luò)數(shù)據(jù) File file = new File() file.write(data)// 持久化到磁盤 file.flush()

          這一過程實(shí)際上發(fā)生了四次數(shù)據(jù)拷貝:

          1. 首先通過 DMA copy 將網(wǎng)絡(luò)數(shù)據(jù)拷貝到內(nèi)核態(tài) Socket Buffer
          2. 然后應(yīng)用程序?qū)?nèi)核態(tài) Buffer 數(shù)據(jù)讀入用戶態(tài)(CPU copy)
          3. 接著用戶程序?qū)⒂脩魬B(tài) Buffer 再拷貝到內(nèi)核態(tài)(CPU copy)
          4. 最后通過 DMA copy 將數(shù)據(jù)拷貝到磁盤文件

          DMA(Direct Memory Access):直接存儲(chǔ)器訪問。DMA 是一種無需 CPU 的參與,讓外設(shè)和系統(tǒng)內(nèi)存之間進(jìn)行雙向數(shù)據(jù)傳輸?shù)挠布C(jī)制。使用 DMA 可以使系統(tǒng) CPU 從實(shí)際的 I/O 數(shù)據(jù)傳輸過程中擺脫出來,從而大大提高系統(tǒng)的吞吐率。

          同時(shí),還伴隨著四次上下文切換,如下圖所示

          數(shù)據(jù)落盤通常都是非實(shí)時(shí)的,kafka 生產(chǎn)者數(shù)據(jù)持久化也是如此。Kafka 的數(shù)據(jù)并不是實(shí)時(shí)的寫入硬盤,它充分利用了現(xiàn)代操作系統(tǒng)分頁存儲(chǔ)來利用內(nèi)存提高 I/O 效率,就是上一節(jié)提到的 Page Cache。

          對(duì)于 kafka 來說,Producer 生產(chǎn)的數(shù)據(jù)存到 broker,這個(gè)過程讀取到 socket buffer 的網(wǎng)絡(luò)數(shù)據(jù),其實(shí)可以直接在內(nèi)核空間完成落盤。并沒有必要將 socket buffer 的網(wǎng)絡(luò)數(shù)據(jù),讀取到應(yīng)用進(jìn)程緩沖區(qū);在這里應(yīng)用進(jìn)程緩沖區(qū)其實(shí)就是 broker,broker 收到生產(chǎn)者的數(shù)據(jù),就是為了持久化。

          在此特殊場(chǎng)景下:接收來自 socket buffer 的網(wǎng)絡(luò)數(shù)據(jù),應(yīng)用進(jìn)程不需要中間處理、直接進(jìn)行持久化時(shí)。可以使用 mmap 內(nèi)存文件映射。

          Memory Mapped Files:簡(jiǎn)稱 mmap,也有叫 MMFile 的,使用 mmap 的目的是將內(nèi)核中讀緩沖區(qū)(read buffer)的地址與用戶空間的緩沖區(qū)(user buffer)進(jìn)行映射。從而實(shí)現(xiàn)內(nèi)核緩沖區(qū)與應(yīng)用程序內(nèi)存的共享,省去了將數(shù)據(jù)從內(nèi)核讀緩沖區(qū)(read buffer)拷貝到用戶緩沖區(qū)(user buffer)的過程。它的工作原理是直接利用操作系統(tǒng)的 Page 來實(shí)現(xiàn)文件到物理內(nèi)存的直接映射。完成映射之后你對(duì)物理內(nèi)存的操作會(huì)被同步到硬盤上。

          使用這種方式可以獲取很大的 I/O 提升,省去了用戶空間到內(nèi)核空間復(fù)制的開銷。

          mmap 也有一個(gè)很明顯的缺陷——不可靠,寫到 mmap 中的數(shù)據(jù)并沒有被真正的寫到硬盤,操作系統(tǒng)會(huì)在程序主動(dòng)調(diào)用 flush 的時(shí)候才把數(shù)據(jù)真正的寫到硬盤。Kafka 提供了一個(gè)參數(shù)——producer.type 來控制是不是主動(dòng)flush;如果 Kafka 寫入到 mmap 之后就立即 flush 然后再返回 Producer 叫同步(sync);寫入 mmap 之后立即返回 Producer 不調(diào)用 flush 就叫異步(async),默認(rèn)是 sync。

          零拷貝(Zero-copy)技術(shù)指在計(jì)算機(jī)執(zhí)行操作時(shí),CPU 不需要先將數(shù)據(jù)從一個(gè)內(nèi)存區(qū)域復(fù)制到另一個(gè)內(nèi)存區(qū)域,從而可以減少上下文切換以及 CPU 的拷貝時(shí)間。

          它的作用是在數(shù)據(jù)報(bào)從網(wǎng)絡(luò)設(shè)備到用戶程序空間傳遞的過程中,減少數(shù)據(jù)拷貝次數(shù),減少系統(tǒng)調(diào)用,實(shí)現(xiàn) CPU 的零參與,徹底消除 CPU 在這方面的負(fù)載。

          目前零拷貝技術(shù)主要有三種類型[3]

          • 直接I/O:數(shù)據(jù)直接跨過內(nèi)核,在用戶地址空間與I/O設(shè)備之間傳遞,內(nèi)核只是進(jìn)行必要的虛擬存儲(chǔ)配置等輔助工作;
          • 避免內(nèi)核和用戶空間之間的數(shù)據(jù)拷貝:當(dāng)應(yīng)用程序不需要對(duì)數(shù)據(jù)進(jìn)行訪問時(shí),則可以避免將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間
            • mmap
            • sendfile
            • splice && tee
            • sockmap
          • copy on write:寫時(shí)拷貝技術(shù),數(shù)據(jù)不需要提前拷貝,而是當(dāng)需要修改的時(shí)候再進(jìn)行部分拷貝。
          4.2 磁盤文件通過網(wǎng)絡(luò)發(fā)送(Broker 到 Consumer)

          傳統(tǒng)方式實(shí)現(xiàn):先讀取磁盤、再用 socket 發(fā)送,實(shí)際也是進(jìn)過四次 copy

          buffer = File.read Socket.send(buffer)

          這一過程可以類比上邊的生產(chǎn)消息:

          1. 首先通過系統(tǒng)調(diào)用將文件數(shù)據(jù)讀入到內(nèi)核態(tài) Buffer(DMA 拷貝)
          2. 然后應(yīng)用程序?qū)?nèi)存態(tài) Buffer 數(shù)據(jù)讀入到用戶態(tài) Buffer(CPU 拷貝)
          3. 接著用戶程序通過 Socket 發(fā)送數(shù)據(jù)時(shí)將用戶態(tài) Buffer 數(shù)據(jù)拷貝到內(nèi)核態(tài) Buffer(CPU 拷貝)
          4. 最后通過 DMA 拷貝將數(shù)據(jù)拷貝到 NIC Buffer

          Linux 2.4+ 內(nèi)核通過 sendfile 系統(tǒng)調(diào)用,提供了零拷貝。數(shù)據(jù)通過 DMA 拷貝到內(nèi)核態(tài) Buffer 后,直接通過 DMA 拷貝到 NIC Buffer,無需 CPU 拷貝。這也是零拷貝這一說法的來源。除了減少數(shù)據(jù)拷貝外,因?yàn)檎麄€(gè)讀文件 - 網(wǎng)絡(luò)發(fā)送由一個(gè) sendfile 調(diào)用完成,整個(gè)過程只有兩次上下文切換,因此大大提高了性能。

          Kafka 在這里采用的方案是通過 NIO 的 transferTo/transferFrom 調(diào)用操作系統(tǒng)的 sendfile 實(shí)現(xiàn)零拷貝。總共發(fā)生 2 次內(nèi)核數(shù)據(jù)拷貝、2 次上下文切換和一次系統(tǒng)調(diào)用,消除了 CPU 數(shù)據(jù)拷貝

          5. 批處理

          在很多情況下,系統(tǒng)的瓶頸不是 CPU 或磁盤,而是網(wǎng)絡(luò)IO。

          因此,除了操作系統(tǒng)提供的低級(jí)批處理之外,Kafka 的客戶端和 broker 還會(huì)在通過網(wǎng)絡(luò)發(fā)送數(shù)據(jù)之前,在一個(gè)批處理中累積多條記錄 (包括讀和寫)。記錄的批處理分?jǐn)偭司W(wǎng)絡(luò)往返的開銷,使用了更大的數(shù)據(jù)包從而提高了帶寬利用率。

          6. 數(shù)據(jù)壓縮

          Producer 可將數(shù)據(jù)壓縮后發(fā)送給 broker,從而減少網(wǎng)絡(luò)傳輸代價(jià),目前支持的壓縮算法有:Snappy、Gzip、LZ4。數(shù)據(jù)壓縮一般都是和批處理配套使用來作為優(yōu)化手段的。

          小總結(jié) | 下次面試官問我 kafka 為什么快,我就這么說

          • partition 并行處理
          • 順序?qū)懘疟P,充分利用磁盤特性
          • 利用了現(xiàn)代操作系統(tǒng)分頁存儲(chǔ) Page Cache 來利用內(nèi)存提高 I/O 效率
          • 采用了零拷貝技術(shù)
            • Producer 生產(chǎn)的數(shù)據(jù)持久化到 broker,采用 mmap 文件映射,實(shí)現(xiàn)順序的快速寫入
            • Customer 從 broker 讀取數(shù)據(jù),采用 sendfile,將磁盤文件讀到 OS 內(nèi)核緩沖區(qū)后,轉(zhuǎn)到 NIO buffer進(jìn)行網(wǎng)絡(luò)發(fā)送,減少 CPU 消耗

          參考資料

          [1]

          美團(tuán)——磁盤I/O那些事: https://tech.meituan.com/2017/05/19/about-desk-io.html

          [2]

          Kafka零拷貝: https://zhuanlan.zhihu.com/p/78335525

          [3]

          Linux - Zero-copy(零拷貝): https://cllc.fun/2020/03/18/linux-zero-copy/


          1.?人人都能看懂的 6 種限流實(shí)現(xiàn)方案!

          2.?一個(gè)空格引發(fā)的“慘案“

          3.?大型網(wǎng)站架構(gòu)演化發(fā)展歷程

          4.?Java語言“坑爹”排行榜TOP 10

          5. 我是一個(gè)Java類(附帶精彩吐槽)

          6. 看完這篇Redis緩存三大問題,保你能和面試官互扯

          7. 程序員必知的 89 個(gè)操作系統(tǒng)核心概念

          8. 深入理解 MySQL:快速學(xué)會(huì)分析SQL執(zhí)行效率

          9. API 接口設(shè)計(jì)規(guī)范

          10. Spring Boot 面試,一個(gè)問題就干趴下了!



          掃碼二維碼關(guān)注我


          ·end·

          —如果本文有幫助,請(qǐng)分享到朋友圈吧—

          我們一起愉快的玩耍!



          你點(diǎn)的每個(gè)贊,我都認(rèn)真當(dāng)成了喜歡

          瀏覽 107
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  亚洲无码视频在线播放 | 黄色视频在线免费看。 | 殴美成人性爱大片免费看 | 黄视频在线最新 | 做受视频一区二区三区 |