Kafka設(shè)計解析(六)- Kafka高性能架構(gòu)之道

Kafka設(shè)計解析(六)- Kafka高性能架構(gòu)之道

原創(chuàng)文章跳座,轉(zhuǎn)載請務(wù)必將下面這段話置于文章開頭處端铛。

本文轉(zhuǎn)發(fā)自技術(shù)世界原文鏈接 http://www.jasongj.com/kafka/high_throughput/

簡介

? 本文從宏觀架構(gòu)層面和微觀實現(xiàn)層面分析了Kafka如何實現(xiàn)高性能疲眷。包含Kafka如何利用Partition實現(xiàn)并行處理和提供水平擴展能力禾蚕,如何通過ISR實現(xiàn)可用性和數(shù)據(jù)一致性的動態(tài)平衡,如何使用NIO和Linux的sendfile實現(xiàn)零拷貝以及如何通過順序讀寫和數(shù)據(jù)壓縮實現(xiàn)磁盤的高效利用狂丝。

宏觀架構(gòu)層面

利用Partition實現(xiàn)并行處理

Partition提供并行處理的能力

Kafka是一個Pub-Sub的消息系統(tǒng)换淆,無論是發(fā)布還是訂閱哗总,都須指定Topic。如《Kafka設(shè)計解析(一)- Kafka背景及架構(gòu)介紹》一文所述倍试,Topic只是一個邏輯的概念讯屈。每個Topic都包含一個或多個Partition,不同Partition可位于不同節(jié)點县习。同時Partition在物理上對應(yīng)一個本地文件夾涮母,每個Partition包含一個或多個Segment,每個Segment包含一個數(shù)據(jù)文件和一個與之對應(yīng)的索引文件躁愿。在邏輯上叛本,可以把一個Partition當(dāng)作一個非常長的數(shù)組,可通過這個“數(shù)組”的索引(offset)去訪問其數(shù)據(jù)攘已。

Topic是邏輯概念
Partition在物理上對應(yīng)一個本地文件夾
Partition = Segment + Segment + Segment + .....
Segment = 數(shù)據(jù)文件 + 索引文件(offset)

一方面炮赦,由于不同Partition可位于不同機器,因此可以充分利用集群優(yōu)勢样勃,實現(xiàn)機器間的并行處理吠勘。另一方面,由于Partition在物理上對應(yīng)一個文件夾峡眶,即使多個Partition位于同一個節(jié)點剧防,也可通過配置讓同一節(jié)點上的不同Partition置于不同的disk drive上,從而實現(xiàn)磁盤間的并行處理辫樱,充分發(fā)揮多磁盤的優(yōu)勢峭拘。

不同的Partition可以位于不同的機器-------實現(xiàn)機器間的并行處理
Partition在物理上對應(yīng)一個文件夾-------實現(xiàn)磁盤間的并行處理

利用多磁盤的具體方法是,將不同磁盤mount到不同目錄狮暑,然后在server.properties中鸡挠,將log.dirs設(shè)置為多目錄(用逗號分隔)。Kafka會自動將所有Partition盡可能均勻分配到不同目錄也即不同目錄(也即不同disk)上搬男。

Kafka自動將所有Partition盡可能均勻分配到不同的disk上

注:雖然物理上最小單位是Segment拣展,但Kafka并不提供同一Partition內(nèi)不同Segment間的并行處理。因為對于寫而言缔逛,每次只會寫Partition內(nèi)的一個Segment备埃,而對于讀而言,也只會順序讀取同一Partition內(nèi)的不同Segment褐奴。

Partition是最小并發(fā)粒度

如同《Kafka設(shè)計解析(四)- Kafka Consumer設(shè)計解析》一文所述按脚,多Consumer消費同一個Topic時,同一條消息只會被同一Consumer Group內(nèi)的一個Consumer所消費敦冬。而數(shù)據(jù)并非按消息為單位分配辅搬,而是以Partition為單位分配,也即同一個Partition的數(shù)據(jù)只會被一個Consumer所消費(在不考慮Rebalance的前提下)脖旱。

同一個Partition只會被一個Consumer消費
Partition個數(shù)決定了可能的最大并行度

如果Consumer的個數(shù)多于Partition的個數(shù)伞辛,那么會有部分Consumer無法消費該Topic的任何數(shù)據(jù)烂翰,也即當(dāng)Consumer個數(shù)超過Partition后,增加Consumer并不能增加并行度蚤氏。

簡而言之,Partition個數(shù)決定了可能的最大并行度踊兜。如下圖所示竿滨,由于Topic 2只包含3個Partition,故group2中的Consumer 3捏境、Consumer 4于游、Consumer 5 可分別消費1個Partition的數(shù)據(jù),而Consumer 6消費不到Topic 2的任何數(shù)據(jù)垫言。


Kafka Consumer

以Spark消費Kafka數(shù)據(jù)為例贰剥,如果所消費的Topic的Partition數(shù)為N,則有效的Spark最大并行度也為N筷频。即使將Spark的Executor數(shù)設(shè)置為N+M蚌成,最多也只有N個Executor可同時處理該Topic的數(shù)據(jù)。

ISR實現(xiàn)可用性與數(shù)據(jù)一致性的動態(tài)平衡

CAP理論

CAP理論是指凛捏,分布式系統(tǒng)中担忧,一致性、可用性和分區(qū)容忍性最多只能同時滿足兩個坯癣。

一致性:consistency

  • 通過某個節(jié)點的寫操作結(jié)果對后面通過其它節(jié)點的讀操作可見
  • 如果更新數(shù)據(jù)后瓶盛,并發(fā)訪問情況下后續(xù)讀操作可立即感知該更新,稱為強一致性
  • 如果允許之后部分或者全部感知不到該更新示罗,稱為弱一致性
  • 若在之后的一段時間(通常該時間不固定)后惩猫,一定可以感知到該更新,稱為最終一致性

可用性:availability

  • 任何一個沒有發(fā)生故障的節(jié)點必須在有限的時間內(nèi)返回合理的結(jié)果

分區(qū)容忍性:Patience

  • 部分節(jié)點宕機或者無法與其它節(jié)點通信時蚜点,各分區(qū)間還可保持分布式系統(tǒng)的功能

常用數(shù)據(jù)復(fù)制及一致性方案

Master-Slave

  • RDBMS的讀寫分離即為典型的Master-Slave方案
  • 同步復(fù)制可保證強一致性但會影響可用性
  • 異步復(fù)制可提供高可用性但會降低一致性

WNR

  • 主要用于去中心化的分布式系統(tǒng)中轧房。DynamoDB與Cassandra即采用此方案或其變種
  • N代表總副本數(shù),W代表每次寫操作要保證的最少寫成功的副本數(shù)禽额,R代表每次讀至少要讀取的副本數(shù)
  • 當(dāng)W+R>N時锯厢,可保證每次讀取的數(shù)據(jù)至少有一個副本擁有最新的數(shù)據(jù)
  • 多個寫操作的順序難以保證,可能導(dǎo)致多副本間的寫操作順序不一致脯倒。Dynamo通過向量時鐘保證最終一致性

Paxos及其變種

  • Google的Chubby实辑,Zookeeper的原子廣播協(xié)議(Zab),RAFT等

基于ISR的數(shù)據(jù)復(fù)制方案

如《 Kafka High Availability(上)》一文所述藻丢,Kafka的數(shù)據(jù)復(fù)制是以Partition為單位的剪撬。而多個備份間的數(shù)據(jù)復(fù)制,通過Follower向Leader拉取數(shù)據(jù)完成悠反。從一這點來講残黑,Kafka的數(shù)據(jù)復(fù)制方案接近于上文所講的Master-Slave方案馍佑。不同的是,Kafka既不是完全的同步復(fù)制梨水,也不是完全的異步復(fù)制拭荤,而是基于ISR的動態(tài)復(fù)制方案。

給予ISR的動態(tài)復(fù)制方案(接近于Master-Slave方案) 

ISR疫诽,也即In-sync Replica舅世。每個Partition的Leader都會維護這樣一個列表,該列表中奇徒,包含了所有與之同步的Replica(包含Leader自己)雏亚。每次數(shù)據(jù)寫入時,只有ISR中的所有Replica都復(fù)制完摩钙,Leader才會將其置為Commit罢低,它才能被Consumer所消費。

ISR由Leader維護

這種方案胖笛,與同步復(fù)制非常接近网持。但不同的是,這個ISR是由Leader動態(tài)維護的匀钧。如果Follower不能緊“跟上”Leader翎碑,它將被Leader從ISR中移除,待它又重新“跟上”Leader后之斯,會被Leader再次加加ISR中日杈。每次改變ISR后,Leader都會將最新的ISR持久化到Zookeeper中佑刷。

至于如何判斷某個Follower是否“跟上”Leader莉擒,不同版本的Kafka的策略稍微有些區(qū)別。

  • 對于0.8.*版本瘫絮,如果Follower在replica.lag.time.max.ms時間內(nèi)未向Leader發(fā)送Fetch請求(也即數(shù)據(jù)復(fù)制請求)涨冀,則Leader會將其從ISR中移除。如果某Follower持續(xù)向Leader發(fā)送Fetch請求麦萤,但是它與Leader的數(shù)據(jù)差距在replica.lag.max.messages以上鹿鳖,也會被Leader從ISR中移除。
  • 從0.9.0.0版本開始壮莹,replica.lag.max.messages被移除翅帜,故Leader不再考慮Follower落后的消息條數(shù)。另外命满,Leader不僅會判斷Follower是否在replica.lag.time.max.ms時間內(nèi)向其發(fā)送Fetch請求漓库,同時還會考慮Follower是否在該時間內(nèi)與之保持同步纤子。
  • 0.10.* 版本的策略與0.9.*版一致

對于0.8.版本的replica.lag.max.messages參數(shù)蚂四,很多讀者曾留言提問,既然只有ISR中的所有Replica復(fù)制完后的消息才被認為Commit杂抽,那為何會出現(xiàn)Follower與Leader差距過大的情況。原因在于韩脏,Leader并不需要等到前一條消息被Commit才接收后一條消息缩麸。事實上,Leader可以按順序接收大量消息骤素,最新的一條消息的Offset被記為High Watermark匙睹。而只有被ISR中所有Follower都復(fù)制過去的消息才會被Commit,Consumer只能消費被Commit的消息济竹。由于Follower的復(fù)制是嚴格按順序的,所以被Commit的消息之前的消息肯定也已經(jīng)被Commit過霎槐。換句話說送浊,High Watermark標(biāo)記的是Leader所保存的最新消息的offset,而Commit Offset標(biāo)記的是最新的可被消費的(已同步到ISR中的Follower)消息丘跌。而Leader對數(shù)據(jù)的接收與Follower對數(shù)據(jù)的復(fù)制是異步進行的袭景,因此會出現(xiàn)Commit Offset與High Watermark存在一定差距的情況。0.8.版本中replica.lag.max.messages限定了Leader允許的該差距的最大值闭树。

Leader接受數(shù)據(jù)和復(fù)制副本數(shù)據(jù)是異步進行的耸棒,Leader按順序接受完消息,將最新的一條消息的offset(偏移)記為High Watermark报辱,而Follower復(fù)制結(jié)束后与殃,commit后標(biāo)記commit offset,所以當(dāng)這兩者的差距拉大碍现,就會出現(xiàn)Follower未能跟上Leader幅疼。

Kafka基于ISR的數(shù)據(jù)復(fù)制方案原理如下圖所示。


Kafka Replication

如上圖所示昼接,在第一步中爽篷,Leader A總共收到3條消息,故其high watermark為3慢睡,但由于ISR中的Follower只同步了第1條消息(m1)逐工,故只有m1被Commit,也即只有m1可被Consumer消費漂辐。此時Follower B與Leader A的差距是1泪喊,而Follower C與Leader A的差距是2,均未超過默認的replica.lag.max.messages者吁,故得以保留在ISR中窘俺。在第二步中,由于舊的Leader A宕機,新的Leader B在replica.lag.time.max.ms時間內(nèi)未收到來自A的Fetch請求瘤泪,故將A從ISR中移除灶泵,此時ISR={B,C}对途。同時赦邻,由于此時新的Leader B中只有2條消息,并未包含m3(m3從未被任何Leader所Commit)实檀,所以m3無法被Consumer消費惶洲。第四步中,F(xiàn)ollower A恢復(fù)正常膳犹,它先將宕機前未Commit的所有消息全部刪除恬吕,然后從最后Commit過的消息的下一條消息開始追趕新的Leader B,直到它“趕上”新的Leader须床,才被重新加入新的ISR中铐料。

藍色線 = commit offset

使用ISR方案的原因

  • 由于Leader可移除不能及時與之同步的Follower,故與同步復(fù)制相比可避免最慢的Follower拖慢整體速度豺旬,也即ISR提高了系統(tǒng)可用性钠惩。
  • ISR中的所有Follower都包含了所有Commit過的消息,而只有Commit過的消息才會被Consumer消費族阅,故從Consumer的角度而言篓跛,ISR中的所有Replica都始終處于同步狀態(tài),從而與異步復(fù)制方案相比提高了數(shù)據(jù)一致性坦刀。
  • ISR可動態(tài)調(diào)整愧沟,極限情況下,可以只包含Leader求泰,極大提高了可容忍的宕機的Follower的數(shù)量央渣。與Majority Quorum方案相比,容忍相同個數(shù)的節(jié)點失敗渴频,所要求的總節(jié)點數(shù)少了近一半芽丹。
避免最慢的Follower拖慢系統(tǒng)的速度
ISR中的所有Replica都處于同步狀態(tài)
極限狀態(tài)下,ISRz中可以只包含Leader  

ISR相關(guān)配置說明

  • Broker的min.insync.replicas參數(shù)指定了Broker所要求的ISR最小長度卜朗,默認值為1拔第。也即極限情況下ISR可以只包含Leader。但此時如果Leader宕機场钉,則該Partition不可用蚊俺,可用性得不到保證。
  • 只有被ISR中所有Replica同步的消息才被Commit逛万,但Producer發(fā)布數(shù)據(jù)時泳猬,Leader并不需要ISR中的所有Replica同步該數(shù)據(jù)才確認收到數(shù)據(jù)。Producer可以通過acks參數(shù)指定最少需要多少個Replica確認收到該消息才視為該消息發(fā)送成功。acks的默認值是1得封,即Leader收到該消息后立即告訴Producer收到該消息埋心,此時如果在ISR中的消息復(fù)制完該消息前Leader宕機,那該條消息會丟失忙上。而如果將該值設(shè)置為0拷呆,則Producer發(fā)送完數(shù)據(jù)后,立即認為該數(shù)據(jù)發(fā)送成功疫粥,不作任何等待茬斧,而實際上該數(shù)據(jù)可能發(fā)送失敗,并且Producer的Retry機制將不生效梗逮。更推薦的做法是项秉,將acks設(shè)置為all或者-1,此時只有ISR中的所有Replica都收到該數(shù)據(jù)(也即該消息被Commit)慷彤,Leader才會告訴Producer該消息發(fā)送成功伙狐,從而保證不會有未知的數(shù)據(jù)丟失。
min.insync.replicas: 1      指定Broker所要求的ISR最小的長度
acks                        指定最少需要多少個Replica確認收到該消息才視為成功

具體實現(xiàn)層面

高效使用磁盤

順序?qū)懘疟P

根據(jù)《一些場景下順序?qū)懘疟P快于隨機寫內(nèi)存》所述瞬欧,將寫磁盤的過程變?yōu)轫樞驅(qū)懀蓸O大提高對磁盤的利用率罢防。

Kafka的整個設(shè)計中艘虎,Partition相當(dāng)于一個非常長的數(shù)組,而Broker接收到的所有消息順序?qū)懭脒@個大數(shù)組中咒吐。同時Consumer通過Offset順序消費這些數(shù)據(jù)野建,并且不刪除已經(jīng)消費的數(shù)據(jù),從而避免了隨機寫磁盤的過程恬叹。

由于磁盤有限候生,不可能保存所有數(shù)據(jù),實際上作為消息系統(tǒng)Kafka也沒必要保存所有數(shù)據(jù)绽昼,需要刪除舊的數(shù)據(jù)唯鸭。而這個刪除過程,并非通過使用“讀-寫”模式去修改文件硅确,而是將Partition分為多個Segment目溉,每個Segment對應(yīng)一個物理文件,通過刪除整個文件的方式去刪除Partition內(nèi)的數(shù)據(jù)菱农。這種方式清除舊數(shù)據(jù)的方式缭付,也避免了對文件的隨機寫操作。

Kafka順序存寫數(shù)據(jù)循未,故刪除時刪除對應(yīng)的Segment(物理文件陷猫,disk),避免對文件的隨機寫操作。

通過如下代碼可知绣檬,Kafka刪除Segment的方式足陨,是直接刪除Segment對應(yīng)的整個log文件和整個index文件而非刪除文件中的部分內(nèi)容。

/**
 * Delete this log segment from the filesystem.
 *
 * @throws KafkaStorageException if the delete fails.
 */
def delete() {
  val deletedLog = log.delete()
  val deletedIndex = index.delete()
  val deletedTimeIndex = timeIndex.delete()
  if(!deletedLog && log.file.exists)
    throw new KafkaStorageException("Delete of log " + log.file.getName + " failed.")
  if(!deletedIndex && index.file.exists)
    throw new KafkaStorageException("Delete of index " + index.file.getName + " failed.")
  if(!deletedTimeIndex && timeIndex.file.exists)
    throw new KafkaStorageException("Delete of time index " + timeIndex.file.getName + " failed.")
}

充分利用Page Cache(分頁緩存)

使用Page Cache的好處如下

  • I/O Scheduler會將連續(xù)的小塊寫組裝成大塊的物理寫從而提高性能
  • I/O Scheduler會嘗試將一些寫操作重新按順序排好河咽,從而減少磁盤頭的移動時間
  • 充分利用所有空閑內(nèi)存(非JVM內(nèi)存)钠右。如果使用應(yīng)用層Cache(即JVM堆內(nèi)存),會增加GC負擔(dān)
  • 讀操作可直接在Page Cache內(nèi)進行忘蟹。如果消費和生產(chǎn)速度相當(dāng)飒房,甚至不需要通過物理磁盤(直接通過Page Cache)交換數(shù)據(jù)
  • 如果進程重啟,JVM內(nèi)的Cache會失效媚值,但Page Cache仍然可用
小塊寫--->大塊寫
寫操作按順序排好
利用所有空閑內(nèi)存
讀操作可直接在Page Cache內(nèi)進行(不是JVM內(nèi)存)

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

斷電會導(dǎo)致Page Cache數(shù)據(jù)丟失
可設(shè)置采用Flush到磁盤,但影響性能

如果數(shù)據(jù)消費速度與生產(chǎn)速度相當(dāng)蹂楣,甚至不需要通過物理磁盤交換數(shù)據(jù)俏站,而是直接通過Page Cache交換數(shù)據(jù)。同時痊土,F(xiàn)ollower從Leader Fetch數(shù)據(jù)時肄扎,也可通過Page Cache完成。下圖為某Partition的Leader節(jié)點的網(wǎng)絡(luò)/磁盤讀寫信息施戴。

Kafka I/O page cache

從上圖可以看到反浓,該Broker每秒通過網(wǎng)絡(luò)從Producer接收約35MB數(shù)據(jù),雖然有Follower從該Broker Fetch數(shù)據(jù)赞哗,但是該Broker基本無讀磁盤雷则。這是因為該Broker直接從Page Cache中將數(shù)據(jù)取出返回給了Follower。

支持多Disk Drive

Broker的log.dirs配置項肪笋,允許配置多個文件夾月劈。如果機器上有多個Disk Drive度迂,可將不同的Disk掛載到不同的目錄,然后將這些目錄都配置到log.dirs里猜揪。Kafka會盡可能將不同的Partition分配到不同的目錄惭墓,也即不同的Disk上,從而充分利用了多Disk的優(yōu)勢而姐。

零拷貝

Kafka中存在大量的網(wǎng)絡(luò)數(shù)據(jù)持久化到磁盤(Producer到Broker)和磁盤文件通過網(wǎng)絡(luò)發(fā)送(Broker到Consumer)的過程腊凶。這一過程的性能直接影響Kafka的整體吞吐量。對比傳統(tǒng)模式的拷貝來看看kafka如何實現(xiàn)零拷貝

傳統(tǒng)模式下的四次拷貝與四次上下文切換

以將磁盤文件通過網(wǎng)絡(luò)發(fā)送為例拴念。傳統(tǒng)模式下钧萍,一般使用如下偽代碼所示的方法先將文件數(shù)據(jù)讀入內(nèi)存,然后通過Socket將內(nèi)存中的數(shù)據(jù)發(fā)送出去政鼠。

buffer = File.read
Socket.send(buffer)

這一過程實際上發(fā)生了四次數(shù)據(jù)拷貝风瘦。首先通過系統(tǒng)調(diào)用將文件數(shù)據(jù)讀入到內(nèi)核態(tài)Buffer(DMA拷貝),然后應(yīng)用程序將內(nèi)存態(tài)Buffer數(shù)據(jù)讀入到用戶態(tài)Buffer(CPU拷貝)公般,接著用戶程序通過Socket發(fā)送數(shù)據(jù)時將用戶態(tài)Buffer數(shù)據(jù)拷貝到內(nèi)核態(tài)Buffer(CPU拷貝)万搔,最后通過DMA拷貝將數(shù)據(jù)拷貝到NIC Buffer(網(wǎng)卡緩沖)。同時官帘,還伴隨著四次上下文切換瞬雹,如下圖所示。

BIO 四次拷貝 四次上下文切換

sendfile和transferTo實現(xiàn)零拷貝

Linux 2.4+內(nèi)核通過sendfile系統(tǒng)調(diào)用刽虹,提供了零拷貝挖炬。數(shù)據(jù)通過DMA拷貝到內(nèi)核態(tài)Buffer后,直接通過DMA(Direct Memory Access状婶,直接內(nèi)存存取)拷貝到NIC Buffer,無需CPU拷貝馅巷。這也是零拷貝這一說法的來源膛虫。除了減少數(shù)據(jù)拷貝外,因為整個讀文件-網(wǎng)絡(luò)發(fā)送由一個sendfile調(diào)用完成钓猬,整個過程只有兩次上下文切換稍刀,因此大大提高了性能。零拷貝過程如下圖所示敞曹。

BIO 零拷貝 兩次上下文切換

從具體實現(xiàn)來看账月,Kafka的數(shù)據(jù)傳輸通過TransportLayer來完成,其子類PlaintextTransportLayer通過Java NIO的FileChannel的transferTotransferFrom方法實現(xiàn)零拷貝澳迫,如下所示局齿。

@Override
public long transferFrom(FileChannel fileChannel, long position, long count) throws IOException {
    return fileChannel.transferTo(position, count, socketChannel);
}

注: transferTotransferFrom并不保證一定能使用零拷貝。實際上是否能使用零拷貝與操作系統(tǒng)相關(guān)橄登,如果操作系統(tǒng)提供sendfile這樣的零拷貝系統(tǒng)調(diào)用抓歼,則這兩個方法會通過這樣的系統(tǒng)調(diào)用充分利用零拷貝的優(yōu)勢讥此,否則并不能通過這兩個方法本身實現(xiàn)零拷貝。

減少網(wǎng)絡(luò)開銷

批處理

批處理是一種常用的用于提高I/O性能的方式谣妻。對Kafka而言萄喳,批處理既減少了網(wǎng)絡(luò)傳輸?shù)腛verhead(天花板),又提高了寫磁盤的效率蹋半。

Kafka 0.8.1及以前的Producer區(qū)分同步Producer和異步Producer他巨。同步Producer的send方法主要分兩種形式。一種是接受一個KeyedMessage作為參數(shù)减江,一次發(fā)送一條消息染突。另一種是接受一批KeyedMessage作為參數(shù),一次性發(fā)送多條消息您市。而對于異步發(fā)送而言觉痛,無論是使用哪個send方法,實現(xiàn)上都不會立即將消息發(fā)送給Broker茵休,而是先存到內(nèi)部的隊列中薪棒,直到消息條數(shù)達到閾值或者達到指定的Timeout才真正的將消息發(fā)送出去,從而實現(xiàn)了消息的批量發(fā)送榕莺。

Kafka 0.8.2開始支持新的Producer API俐芯,將同步Producer和異步Producer結(jié)合。雖然從send接口來看钉鸯,一次只能發(fā)送一個ProducerRecord吧史,而不能像之前版本的send方法一樣接受消息列表,但是send方法并非立即將消息發(fā)送出去唠雕,而是通過batch.sizelinger.ms控制實際發(fā)送頻率贸营,從而實現(xiàn)批量發(fā)送。

由于每次網(wǎng)絡(luò)傳輸岩睁,除了傳輸消息本身以外钞脂,還要傳輸非常多的網(wǎng)絡(luò)協(xié)議本身的一些內(nèi)容(稱為Overhead),所以將多條消息合并到一起傳輸捕儒,可有效減少網(wǎng)絡(luò)傳輸?shù)腛verhead冰啃,進而提高了傳輸效率。

從零拷貝章節(jié)的圖中可以看到刘莹,雖然Broker持續(xù)從網(wǎng)絡(luò)接收數(shù)據(jù)阎毅,但是寫磁盤并非每秒都在發(fā)生,而是間隔一段時間寫一次磁盤点弯,并且每次寫磁盤的數(shù)據(jù)量都非常大(最高達到718MB/S)扇调。

數(shù)據(jù)壓縮降低網(wǎng)絡(luò)負載

Kafka從0.7開始,即支持將數(shù)據(jù)壓縮后再傳輸給Broker抢肛。除了可以將每條消息單獨壓縮然后傳輸外肃拜,Kafka還支持在批量發(fā)送時痴腌,將整個Batch的消息一起壓縮后傳輸。數(shù)據(jù)壓縮的一個基本原理是燃领,重復(fù)數(shù)據(jù)越多壓縮效果越好士聪。因此將整個Batch的數(shù)據(jù)一起壓縮能更大幅度減小數(shù)據(jù)量,從而更大程度提高網(wǎng)絡(luò)傳輸效率猛蔽。

Broker接收消息后剥悟,并不直接解壓縮,而是直接將消息以壓縮后的形式持久化到磁盤曼库。Consumer Fetch到數(shù)據(jù)后再解壓縮区岗。因此Kafka的壓縮不僅減少了Producer到Broker的網(wǎng)絡(luò)傳輸負載,同時也降低了Broker磁盤操作的負載毁枯,也降低了Consumer與Broker間的網(wǎng)絡(luò)傳輸量慈缔,從而極大得提高了傳輸效率,提高了吞吐量种玛。

1 單條/Batch壓縮---傳輸----持久化到磁盤---Consumer Fetch到數(shù)據(jù)后再解壓縮
2 降低了Broker磁盤操作的負擔(dān)藐鹤,降低了Consumer與Broker間的網(wǎng)絡(luò)傳輸量 提高了傳輸效率 提高了   吞吐率

高效的序列化方式

Kafka消息的Key和Payload(或者說Value)的類型可自定義,只需同時提供相應(yīng)的序列化器和反序列化器即可赂韵。因此用戶可以通過使用快速且緊湊的序列化-反序列化方式(如Avro娱节,Protocal Buffer)來減少實際網(wǎng)絡(luò)傳輸和磁盤存儲的數(shù)據(jù)規(guī)模,從而提高吞吐率祭示。這里要注意肄满,如果使用的序列化方法太慢,即使壓縮比非常高质涛,最終的效率也不一定高稠歉。

Kafka系列文章

Kafka設(shè)計解析(一)- Kafka簡介及架構(gòu)介紹
Kafka設(shè)計解析(二)- Kafka High Availability (上)
Kafka設(shè)計解析(三)- Kafka High Availability (下)
Kafka設(shè)計解析(四)- Kafka Consumer設(shè)計解析
Kafka設(shè)計解析(五)- Kafka性能測試方法及Benchmark報告
Kafka設(shè)計解析(六)- Kafka高性能架構(gòu)之道
Kafka設(shè)計解析(七)- Kafka Stream

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市汇陆,隨后出現(xiàn)的幾起案子轧抗,更是在濱河造成了極大的恐慌,老刑警劉巖瞬测,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異纠炮,居然都是意外死亡月趟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門恢口,熙熙樓的掌柜王于貴愁眉苦臉地迎上來孝宗,“玉大人,你說我怎么就攤上這事耕肩∫蚋荆” “怎么了问潭?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長婚被。 經(jīng)常有香客問我狡忙,道長,這世上最難降的妖魔是什么址芯? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任灾茁,我火速辦了婚禮,結(jié)果婚禮上谷炸,老公的妹妹穿的比我還像新娘北专。我一直安慰自己,他們只是感情好旬陡,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布拓颓。 她就那樣靜靜地躺著,像睡著了一般描孟。 火紅的嫁衣襯著肌膚如雪驶睦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天画拾,我揣著相機與錄音啥繁,去河邊找鬼。 笑死青抛,一個胖子當(dāng)著我的面吹牛旗闽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜜另,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼适室,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了举瑰?” 一聲冷哼從身側(cè)響起捣辆,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎此迅,沒想到半個月后汽畴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡耸序,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年忍些,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坎怪。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡罢坝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出搅窿,到底是詐尸還是另有隱情嘁酿,我是刑警寧澤隙券,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站闹司,受9級特大地震影響娱仔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜开仰,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一拟枚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧众弓,春花似錦恩溅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至滨达,卻和暖如春奶稠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捡遍。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工锌订, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人画株。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓辆飘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谓传。 傳聞我的和親對象是個殘疾皇子蜈项,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容