kafka核心架構詳解

Fresh_man888發表於2020-11-14

目錄

1.什麼是kafka

2.什麼是訊息佇列

3. 為什麼使用訊息佇列

4.kafka的特點:

5.kafka的應用場景

6. kafka系統的架構基礎(重點)

6.1 kafka系統架構中各元件的名稱以及用途:

7. kafka中的命令列操作

8. kafkaJAVA中的API模擬生產者和消費者

8.1 一個正常的生產者和消費的的邏輯是:

8.2 生產者程式碼實現


1.什麼是kafka

Kafka是一個分散式訊息中介軟體,支援分割槽的、多副本的、多訂閱者的、基於zookeeper協調的分散式訊息系統。

通俗來說: kafka就是一個儲存系統,儲存的資料形式為“訊息”;

它的主要作用類似於蓄水池,起到一個緩衝作用

2.什麼是訊息佇列

常見的訊息佇列有activemq ,rabbitmq, rocketmq;

訊息佇列常用於兩個系統之間資料傳遞

分散式訊息傳遞基於可靠的訊息佇列,在客戶端應用和訊息系統之間非同步傳遞訊息。

有兩種主要的訊息傳遞模式:點對點傳遞模式、釋出-訂閱模式。

kafka採用的就是釋出-訂閱模式

3. 為什麼使用訊息佇列

優點:非同步,削峰,解耦

4.kafka的特點:

  1. 高吞吐量、低延遲:kafka每秒可以處理幾十萬條訊息,它的延遲最低只有幾毫秒,每個topic可以分多個partition, 由多個consumer group 對partition進行consume操作。
  2. 可擴充套件性:kafka叢集支援熱擴充套件
  3. 永續性、可靠性:訊息被持久化到本地磁碟,並且支援資料備份防止資料丟失
  4. 容錯性:允許叢集中節點失敗(若副本數量為n,則允許n-1個節點失敗)
  5. 高併發:支援數千個客戶端同時讀寫

5.kafka的應用場景

主要用於資料處理系統中的緩衝!

6. kafka系統的架構基礎(重點)

6.1 kafka系統架構中各元件的名稱以及用途:

1) producer:訊息生產者

訊息生產者,就是向kafka broker 發訊息的客戶端。

2) consumer:訊息消費者

consumer :訊息消費者,從kafka broker 取訊息的客戶端。

consumer group:單個或多個consumer可以組成一個consumer group;這是 kafka 用來實現訊息的廣播(發給所有的 consumer)和單播(發給任意一個 consumer)的手段。一個 topic 可以有多個Consumer Group。

3 ) topic:資料的邏輯分類,可以理解為資料庫中表的概念,topic又進一步分為patition , broker , offset

  1. partition: topic中資料的具體管理單元;(你可以理解為hbase中表的“region”概念)一個topic 可以劃分為多個partition,分佈到多個 broker上管理;每個partition由一個kafka broker伺服器管理;partition 中的每條訊息都會被分配一個遞增的id(offset);每個 partition 是一個有序的佇列,kafka 只保證按一個 partition 中的訊息的順序,不保證一個 topic 的整體(多個 partition 間)的順序。每個partition都可以有多個副本;
  2. broker:一臺kafka伺服器就是一個broker.kafka叢集就是由多個broker組成,一個broker可以有多個topic的多個partition;
  3. offset:訊息在底層儲存中的索引位置,kafka底層的儲存檔案就是以檔案中第一條訊息的offset來命名的,通過offset可以快速定位到訊息的具體儲存位置;             
  4. 小結:分割槽對於 kafka 叢集的好處是:實現topic資料的負載均衡。分割槽對於消費者來說,可以提高併發度,提高效率

4) Leader:partition 副本中的一個角色,生產者和消費者只跟leader進行讀寫互動

partition replica中的一個角色,producer和consumer只跟leader互動(負責讀寫)。

5) 副本Replica:

partition的副本,保障partition的高可用(replica副本數目不能大於kafka broker節點的數目,否則報錯。每個partition的所有副本中,必包括一個leader副本,其他的就是follower副本

6) follower

partition replica中的一個角色,從leader中拉取複製資料(只負責備份)。

如果leader所在節點當機,follower中會選舉出新的leader;

7) 偏移量Offset

每一條資料都有一個offset,是資料在該partition中的唯一標識(其實就是訊息的索引號)。

各個consumer會儲存其消費到的offset位置,這樣下次可以從該offset位置開始繼續消費;

consumer的消費offset儲存在一個專門的topic(__consumer_offsets)中;(0.10.x版本以前是儲存在zk中)

8)  訊息Message

每一條massage是由一對key-value構成

組成massage format是由:

  1. Crc:主要用於校驗訊息的內容
  2. magic:主要用於標識 Kafka 版本。
  3. attribute:這裡面儲存了訊息壓縮使用的編碼以及Timestamp型別
  4. key length:主要標識 Key的內容的長度
  5. key:佔用 N個位元組,儲存的是 key 的具體內容;
  6. values length:主要標識 value 的內容的長度
  7. value:value即是訊息的真實內容,在 Kafka 中這個也叫做payload

7. kafka中的命令列操作

1) 建立topic

./kafka-topics.sh --zookeeper linux01:2181,linux02:2181,linux03:2181 --create --replication-factor 3 --partitions 3 --topic tpc_1

引數解釋:

--replication-factor  副本數量

--partitions 分割槽數量

--topic topic名稱

2) 建立topic:手動指定副本的儲存位置

bin/kafka-topics.sh --create --topic tpc_1  --zookeeper linux01:2181 --replica-assignment 0:1,1:2

會自動判斷,要建立的topic的分割槽數及副本數以及每個副本所在的broker的位置

3) 檢視當前系統中的所有topic

bin/kafka-topics.sh --zookeeper doitedu01:2181,doitedu02:2181,doitedu03:2181 --list

4) 刪除topic

bin/kafka-topics.sh --zookeeper doitedu01:2181,doitedu02:2181,doitedu03:2181 --delete --topic test

刪除topic,需要一個引數處於啟用狀態: delete.topic.enable = true

5) 檢視某個topic的詳情

 bin/kafka-topics.sh  --zookeeper linux01:2181linux02:2181 linux03:2181 --describe --topic tpc_1

Topic:tpc_1     PartitionCount:3        ReplicationFactor:3     Configs:
        Topic: tpc_1    Partition: 0    Leader: 1       Replicas: 1,0,2 Isr: 1,0,2
        Topic: tpc_1    Partition: 1    Leader: 2       Replicas: 2,1,0 Isr: 2,1,0
        Topic: tpc_1    Partition: 2    Leader: 0       Replicas: 0,2,1 Isr: 0,2,1

結果解讀:

從上面的結果中,可以看出,topic的分割槽數量,以及每個分割槽的副本數量,以及每個副本所在的broker節點,以及每個分割槽的leader副本所在broker節點,以及每個分割槽的ISR副本列表;

ISR: in  sync  replicas  同步副本

OSR:out  of  sync replicas 失去同步的副本(資料與leader之間的差距超過配置的閾值)

6)修改分割槽數

Kafka只支援增加分割槽,不支援減少分割槽

原因是:減少分割槽,代價太大(資料的轉移,日誌段拼接合並)

7) topic的動態引數更新

bin/kafka-configs.sh --zookeeper linux01:2181 --entity-type topics --entity-name tpc_1 --alter --add-config compression.type=gzip//新增動態引數命令

Topic:tpc_1     PartitionCount:3        ReplicationFactor:3     Configs:compression.type=gzip
        Topic: tpc_1    Partition: 0    Leader: 1       Replicas: 1,0,2 Isr: 1,0,2
        Topic: tpc_1    Partition: 1    Leader: 2       Replicas: 2,1,0 Isr: 2,1,0
        Topic: tpc_1    Partition: 2    Leader: 0       Replicas: 0,2,1 Isr: 0,2,1

bin/kafka-configs.sh --zookeeper linux01:2181 --entity-type topics --entity-name tpc_1 --alter --delete-config compression.type  //這個是刪除引數命令

8) 命令列的producer開啟producer

bin/kafka-console-producer.sh --broker-list linux01:9092 --topic tpc_1

9) 命令列consumer

bin/kafka-console-consumer.sh --bootstrap-server  linux01:9092  --from-beginning --topic tpc_1    //在命令列中消費訊息

10) 指定要消費的分割槽,和要消費的其實offset

bin/kafka-console-consumer.sh --bootstrap-server linux01:9092,linux02:9092,linux03:9092 --topic tpc_1 --offset 2 --partition 0

8. kafkaJAVA中的API模擬生產者和消費者

8.1 一個正常的生產者和消費的的邏輯是:

一個正常的生產邏輯需要具備以下幾個步驟

(1)配置生產者客戶端引數及建立相應的生產者例項

(2)構建待傳送的訊息

(3)傳送訊息

(4)關閉生產者例項

8.2 生產者程式碼實現

package com.zxx.kafka.day01.demo;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;

import java.util.Properties;

/**
 * @Classname KafkaDemo2
 * @Date 2020/11/14 21:30
 * @Created by zxx
 * @Description
 */
public class KafkaDemo2 {
    public static void main(String[] args) {
        //設定配置檔案
        Properties props = new Properties();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"linux01:9092,linux02:9092,linux03:9092");
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
        props.put(ProducerConfig.ACKS_CONFIG,"all");
        // 涉及到一個重要的原理知識:kafka的冪等性
        props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG,"false");
        //建立一個生產者的例項物件
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);
        for (int i = 0; i < 10000; i++) {
            ProducerRecord<String, String> tpc_2 = new ProducerRecord<>("tpc_2", "name" + i, RandomStringUtils.randomAscii(15));
            producer.send(tpc_2);
        }
        producer.close();


    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相關文章