Kafka的分區(qū)數(shù)和消費(fèi)者個(gè)數(shù)

Kafka的分區(qū)數(shù)是不是越多越好骏掀?

分區(qū)多的優(yōu)點(diǎn)

kafka使用分區(qū)將topic的消息打散到多個(gè)分區(qū)分布保存在不同的broker上突诬,實(shí)現(xiàn)了producer和consumer消息處理的高吞吐量伞插。Kafka的producer和consumer都可以多線程地并行操作,而每個(gè)線程處理的是一個(gè)分區(qū)的數(shù)據(jù)。因此分區(qū)實(shí)際上是調(diào)優(yōu)Kafka并行度的最小單元写妥。對(duì)于producer而言,它實(shí)際上是用多個(gè)線程并發(fā)地向不同分區(qū)所在的broker發(fā)起Socket連接同時(shí)給這些分區(qū)發(fā)送消息审姓;而consumer珍特,同一個(gè)消費(fèi)組內(nèi)的所有consumer線程都被指定topic的某一個(gè)分區(qū)進(jìn)行消費(fèi)。

所以說魔吐,如果一個(gè)topic分區(qū)越多扎筒,理論上整個(gè)集群所能達(dá)到的吞吐量就越大。

分區(qū)不是越多越好

分區(qū)是否越多越好呢酬姆?顯然也不是嗜桌,因?yàn)槊總€(gè)分區(qū)都有自己的開銷:

一、客戶端/服務(wù)器端需要使用的內(nèi)存就越多 Kafka0.8.2之后轴踱,在客戶端producer有個(gè)參數(shù)batch.size症脂,默認(rèn)是16KB。它會(huì)為每個(gè)分區(qū)緩存消息淫僻,一旦滿了就打包將消息批量發(fā)出诱篷。看上去這是個(gè)能夠提升性能的設(shè)計(jì)雳灵。不過很顯然棕所,因?yàn)檫@個(gè)參數(shù)是分區(qū)級(jí)別的,如果分區(qū)數(shù)越多悯辙,這部分緩存所需的內(nèi)存占用也會(huì)更多琳省。假設(shè)你有10000個(gè)分區(qū)迎吵,按照默認(rèn)設(shè)置,這部分緩存需要占用約157MB的內(nèi)存针贬。而consumer端呢击费?我們拋開獲取數(shù)據(jù)所需的內(nèi)存不說,只說線程的開銷桦他。如果還是假設(shè)有10000個(gè)分區(qū)蔫巩,同時(shí)consumer線程數(shù)要匹配分區(qū)數(shù)(大部分情況下是最佳的消費(fèi)吞吐量配置)的話,那么在consumer client就要?jiǎng)?chuàng)建10000個(gè)線程快压,也需要?jiǎng)?chuàng)建大約10000個(gè)Socket去獲取分區(qū)數(shù)據(jù)圆仔。這里面的線程切換的開銷本身已經(jīng)不容小覷了。
服務(wù)器端的開銷也不小蔫劣,如果閱讀Kafka源碼的話可以發(fā)現(xiàn)坪郭,服務(wù)器端的很多組件都在內(nèi)存中維護(hù)了分區(qū)級(jí)別的緩存,比如controller脉幢,F(xiàn)etcherManager等歪沃,因此分區(qū)數(shù)越多,這種緩存的成本就越大鸵隧。
二绸罗、文件句柄的開銷 每個(gè)分區(qū)在底層文件系統(tǒng)都有屬于自己的一個(gè)目錄。該目錄下通常會(huì)有兩個(gè)文件: base_offset.log和base_offset.index豆瘫。Kafak的controller和ReplicaManager會(huì)為每個(gè)broker都保存這兩個(gè)文件句柄(file handler)珊蟀。很明顯,如果分區(qū)數(shù)越多外驱,所需要保持打開狀態(tài)的文件句柄數(shù)也就越多育灸,最終可能會(huì)突破你的ulimit -n的限制。
三昵宇、降低高可用性 Kafka通過副本(replica)機(jī)制來保證高可用磅崭。具體做法就是為每個(gè)分區(qū)保存若干個(gè)副本(replica_factor指定副本數(shù))。每個(gè)副本保存在不同的broker上瓦哎。期中的一個(gè)副本充當(dāng)leader 副本砸喻,負(fù)責(zé)處理producer和consumer請(qǐng)求。其他副本充當(dāng)follower角色蒋譬,由Kafka controller負(fù)責(zé)保證與leader的同步割岛。如果leader所在的broker掛掉了,contorller會(huì)檢測(cè)到然后在zookeeper的幫助下重選出新的leader——這中間會(huì)有短暫的不可用時(shí)間窗口犯助,雖然大部分情況下可能只是幾毫秒級(jí)別癣漆。但如果你有10000個(gè)分區(qū),10個(gè)broker剂买,也就是說平均每個(gè)broker上有1000個(gè)分區(qū)惠爽。此時(shí)這個(gè)broker掛掉了癌蓖,那么zookeeper和controller需要立即對(duì)這1000個(gè)分區(qū)進(jìn)行l(wèi)eader選舉。比起很少的分區(qū)leader選舉而言婚肆,這必然要花更長(zhǎng)的時(shí)間租副,并且通常不是線性累加的。如果這個(gè)broker還同時(shí)是controller情況就更糟了旬痹。

如何確定分區(qū)數(shù)量呢

可以遵循一定的步驟來嘗試確定分區(qū)數(shù):創(chuàng)建一個(gè)只有1個(gè)分區(qū)的topic附井,然后測(cè)試這個(gè)topic的producer吞吐量和consumer吞吐量。假設(shè)它們的值分別是Tp和Tc两残,單位可以是MB/s。然后假設(shè)總的目標(biāo)吞吐量是Tt把跨,那么分區(qū)數(shù) = Tt / max(Tp, Tc)

說明:Tp表示producer的吞吐量人弓。測(cè)試producer通常是很容易的,因?yàn)樗倪壿嫹浅:?jiǎn)單着逐,就是直接發(fā)送消息到Kafka就好了崔赌。Tc表示consumer的吞吐量。測(cè)試Tc通常與應(yīng)用的關(guān)系更大耸别, 因?yàn)門c的值取決于你拿到消息之后執(zhí)行什么操作健芭,因此Tc的測(cè)試通常也要麻煩一些。

一條消息如何知道要被發(fā)送到哪個(gè)分區(qū)秀姐?

按照key值分配

默認(rèn)情況下慈迈,Kafka根據(jù)傳遞消息的key來進(jìn)行分區(qū)的分配,即hash(key) % numPartitions:

def partition(key: Any, numPartitions: Int): Int = {
    Utils.abs(key.hashCode) % numPartitions
}

這保證了相同key的消息一定會(huì)被路由到相同的分區(qū)省有。

key為null時(shí)痒留,從緩存中取分區(qū)id或者隨機(jī)取一個(gè)

如果你沒有指定key,那么Kafka是如何確定這條消息去往哪個(gè)分區(qū)的呢蠢沿?

if(key == null) {  // 如果沒有指定key
    val id = sendPartitionPerTopicCache.get(topic)  // 先看看Kafka有沒有緩存的現(xiàn)成的分區(qū)Id
    id match {
      case Some(partitionId) =>  
        partitionId  // 如果有的話直接使用這個(gè)分區(qū)Id就好了
      case None => // 如果沒有的話伸头,
        val availablePartitions = topicPartitionList.filter(_.leaderBrokerIdOpt.isDefined)  //找出所有可用分區(qū)的leader所在的broker
        if (availablePartitions.isEmpty)
          throw new LeaderNotAvailableException("No leader for any partition in topic " + topic)
        val index = Utils.abs(Random.nextInt) % availablePartitions.size  // 從中隨機(jī)挑一個(gè)
        val partitionId = availablePartitions(index).partitionId
        sendPartitionPerTopicCache.put(topic, partitionId) // 更新緩存以備下一次直接使用
        partitionId
    }
}

不指定key時(shí),Kafka幾乎就是隨機(jī)找一個(gè)分區(qū)發(fā)送無key的消息舷蟀,然后把這個(gè)分區(qū)號(hào)加入到緩存中以備后面直接使用——當(dāng)然了恤磷,Kafka本身也會(huì)清空該緩存(默認(rèn)每10分鐘或每次請(qǐng)求topic元數(shù)據(jù)時(shí))。

Consumer個(gè)數(shù)與分區(qū)數(shù)有什么關(guān)系野宜?

topic下的一個(gè)分區(qū)只能被同一個(gè)consumer group下的一個(gè)consumer線程來消費(fèi)扫步,但反之并不成立,即一個(gè)consumer線程可以消費(fèi)多個(gè)分區(qū)的數(shù)據(jù)速缨,比如Kafka提供的ConsoleConsumer锌妻,默認(rèn)就只是一個(gè)線程來消費(fèi)所有分區(qū)的數(shù)據(jù)。

即分區(qū)數(shù)決定了同組消費(fèi)者個(gè)數(shù)的上限

image.png

所以旬牲,如果你的分區(qū)數(shù)是N仿粹,那么最好線程數(shù)也保持為N搁吓,這樣通常能夠達(dá)到最大的吞吐量。超過N的配置只是浪費(fèi)系統(tǒng)資源吭历,因?yàn)槎喑龅木€程不會(huì)被分配到任何分區(qū)堕仔。

Consumer消費(fèi)Partition的分配策略

Kafka提供的兩種分配策略: range和roundrobin,由參數(shù)partition.assignment.strategy指定晌区,默認(rèn)是range策略摩骨。

當(dāng)以下事件發(fā)生時(shí),Kafka 將會(huì)進(jìn)行一次分區(qū)分配:

  • 同一個(gè) Consumer Group 內(nèi)新增消費(fèi)者
  • 消費(fèi)者離開當(dāng)前所屬的Consumer Group朗若,包括shuts down 或 crashes
  • 訂閱的主題新增分區(qū)

將分區(qū)的所有權(quán)從一個(gè)消費(fèi)者移到另一個(gè)消費(fèi)者稱為重新平衡(rebalance)恼五,如何rebalance就涉及到本文提到的分區(qū)分配策略。
下面我們將詳細(xì)介紹 Kafka 內(nèi)置的兩種分區(qū)分配策略哭懈。本文假設(shè)我們有個(gè)名為 T1 的主題灾馒,其包含了10個(gè)分區(qū),然后我們有兩個(gè)消費(fèi)者(C1遣总,C2)
來消費(fèi)這10個(gè)分區(qū)里面的數(shù)據(jù)睬罗,而且 C1 的 num.streams = 1,C2 的 num.streams = 2旭斥。

Range strategy

Range策略是對(duì)每個(gè)主題而言的容达,首先對(duì)同一個(gè)主題里面的分區(qū)按照序號(hào)進(jìn)行排序,并對(duì)消費(fèi)者按照字母順序進(jìn)行排序垂券。在我們的例子里面花盐,排完序的分區(qū)將會(huì)是0, 1, 2, 3, 4, 5, 6, 7, 8, 9;消費(fèi)者線程排完序?qū)?huì)是C1-0, C2-0, C2-1圆米。然后將partitions的個(gè)數(shù)除于消費(fèi)者線程的總數(shù)來決定每個(gè)消費(fèi)者線程消費(fèi)幾個(gè)分區(qū)卒暂。如果除不盡,那么前面幾個(gè)消費(fèi)者線程將會(huì)多消費(fèi)一個(gè)分區(qū)娄帖。在我們的例子里面也祠,我們有10個(gè)分區(qū),3個(gè)消費(fèi)者線程近速, 10 / 3 = 3诈嘿,而且除不盡,那么消費(fèi)者線程 C1-0 將會(huì)多消費(fèi)一個(gè)分區(qū)削葱,所以最后分區(qū)分配的結(jié)果看起來是這樣的:

  • C1-0 將消費(fèi) 0, 1, 2, 3 分區(qū)
  • C2-0 將消費(fèi) 4, 5, 6 分區(qū)
  • C2-1 將消費(fèi) 7, 8, 9 分區(qū)

假如我們有11個(gè)分區(qū)奖亚,那么最后分區(qū)分配的結(jié)果看起來是這樣的:

  • C1-0 將消費(fèi) 0, 1, 2, 3 分區(qū)
  • C2-0 將消費(fèi) 4, 5, 6, 7 分區(qū)
  • C2-1 將消費(fèi) 8, 9, 10 分區(qū)

假如我們有2個(gè)主題(T1和T2),分別有10個(gè)分區(qū)析砸,那么最后分區(qū)分配的結(jié)果看起來是這樣的:

  • C1-0 將消費(fèi) T1主題的 0, 1, 2, 3 分區(qū)以及 T2主題的 0, 1, 2, 3分區(qū)
  • C2-0 將消費(fèi) T1主題的 4, 5, 6 分區(qū)以及 T2主題的 4, 5, 6分區(qū)
  • C2-1 將消費(fèi) T1主題的 7, 8, 9 分區(qū)以及 T2主題的 7, 8, 9分區(qū)

可以看出昔字,C1-0 消費(fèi)者線程比其他消費(fèi)者線程多消費(fèi)了2個(gè)分區(qū),這就是Range strategy的一個(gè)很明顯的弊端。

RoundRobin strategy

使用RoundRobin策略有兩個(gè)前提條件必須滿足:

  • 同一個(gè)Consumer Group里面的所有消費(fèi)者的num.streams必須相等作郭;
  • 每個(gè)消費(fèi)者訂閱的主題必須相同陨囊。

所以這里假設(shè)前面提到的2個(gè)消費(fèi)者的num.streams = 2。RoundRobin策略的工作原理:將所有主題的分區(qū)組成 TopicAndPartition 列表夹攒,然后對(duì) TopicAndPartition 列表按照 hashCode 進(jìn)行排序蜘醋,看下面的代碼應(yīng)該會(huì)明白:

val allTopicPartitions = ctx.partitionsForTopic.flatMap { case(topic, partitions) =>
  info("Consumer %s rebalancing the following partitions for topic %s: %s"
       .format(ctx.consumerId, topic, partitions))
  partitions.map(partition => {
    TopicAndPartition(topic, partition)
  })
}.toSeq.sortWith((topicPartition1, topicPartition2) => {
  /*
   * Randomize the order by taking the hashcode to reduce the likelihood of all partitions of a given topic ending
   * up on one consumer (if it has a high enough stream count).
   */
  topicPartition1.toString.hashCode < topicPartition2.toString.hashCode
})

最后按照round-robin風(fēng)格將分區(qū)分別分配給不同的消費(fèi)者線程。

在這個(gè)的例子里面咏尝,假如按照 hashCode 排序完的topic-partitions組依次為T1-5, T1-3, T1-0, T1-8, T1-2, T1-1, T1-4, T1-7, T1-6, T1-9压语,我們的消費(fèi)者線程排序?yàn)镃1-0, C1-1, C2-0, C2-1,最后分區(qū)分配的結(jié)果為:

  • C1-0 將消費(fèi) T1-5, T1-2, T1-6 分區(qū)编检;
  • C1-1 將消費(fèi) T1-3, T1-1, T1-9 分區(qū)胎食;
  • C2-0 將消費(fèi) T1-0, T1-4 分區(qū);
  • C2-1 將消費(fèi) T1-8, T1-7 分區(qū)允懂;

多個(gè)主題的分區(qū)分配和單個(gè)主題類似斥季。遺憾的是,目前我們還不能自定義分區(qū)分配策略累驮,只能通過partition.assignment.strategy參數(shù)選擇 range 或 roundrobin。

本文轉(zhuǎn)載自https://blog.csdn.net/OiteBody/article/details/80595971

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末舵揭,一起剝皮案震驚了整個(gè)濱河市谤专,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌午绳,老刑警劉巖置侍,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拦焚,居然都是意外死亡蜡坊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門赎败,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秕衙,“玉大人,你說我怎么就攤上這事僵刮【萃” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵搞糕,是天一觀的道長(zhǎng)勇吊。 經(jīng)常有香客問我,道長(zhǎng)窍仰,這世上最難降的妖魔是什么汉规? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮驹吮,結(jié)果婚禮上针史,老公的妹妹穿的比我還像新娘晶伦。我一直安慰自己,他們只是感情好悟民,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布坝辫。 她就那樣靜靜地躺著,像睡著了一般射亏。 火紅的嫁衣襯著肌膚如雪近忙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天智润,我揣著相機(jī)與錄音及舍,去河邊找鬼。 笑死窟绷,一個(gè)胖子當(dāng)著我的面吹牛锯玛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兼蜈,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼攘残,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了为狸?” 一聲冷哼從身側(cè)響起歼郭,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辐棒,沒想到半個(gè)月后病曾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡漾根,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年泰涂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辐怕。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逼蒙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秘蛇,到底是詐尸還是另有隱情其做,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布赁还,位于F島的核電站妖泄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏艘策。R本人自食惡果不足惜蹈胡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧罚渐,春花似錦却汉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至源织,卻和暖如春翩伪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谈息。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工缘屹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侠仇。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓轻姿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親逻炊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子互亮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 姓名:周小蓬 16019110037 轉(zhuǎn)載自:http://blog.csdn.net/YChenFeng/art...
    aeytifiw閱讀 34,708評(píng)論 13 425
  • Kafka簡(jiǎn)介 Kafka是一種分布式的,基于發(fā)布/訂閱的消息系統(tǒng)余素。主要設(shè)計(jì)目標(biāo)如下: 以時(shí)間復(fù)雜度為O(1)的方...
    Alukar閱讀 3,074評(píng)論 0 43
  • 消費(fèi)者如何分配分區(qū)就是指某個(gè)topic胳挎,其N個(gè)分區(qū)和消費(fèi)該topic的若干消費(fèi)者群組下M個(gè)消費(fèi)者的關(guān)系。如下圖所示...
    阿飛的博客閱讀 6,332評(píng)論 10 9
  • 本文轉(zhuǎn)載自http://dataunion.org/?p=9307 背景介紹Kafka簡(jiǎn)介Kafka是一種分布式的...
    Bottle丶Fish閱讀 5,433評(píng)論 0 34
  • “韓信那個(gè)死變態(tài)這幾天怎么沒來溺森?”王者峽谷在寒風(fēng)中瑟瑟發(fā)抖的藍(lán)爸爸說道。 “平常都是這個(gè)點(diǎn)窑眯,日常偷豬的韓信會(huì)準(zhǔn)時(shí)來...
    修行什么的不存在閱讀 504評(píng)論 4 3