大數據技術學習之Kafka基本原理

Kafka基本原理

Apache Kafka是分布式發布-訂閱消息系統。它最初由LinkedIn公司開發,之后成為Apache項目的一部分。Kafka是一種快速、可擴展的、設計內在就是分布式的,分區的和可復制的提交日志服務。

Kafka架構組件

話題(Topic):是特定類型的消息流。消息是字節的有效負載(Payload),話題是消息的分類名或種子(Feed)名。

生產者(Producer):是能夠發布消息到話題的任何對象。

服務代理(Broker):已發布的消息保存在一組服務器中,它們被稱為代理(Broker)或Kafka集群。

消費者(Consumer):可以訂閱一個或多個話題,并從Broker拉數據,從而消費這些已發布的消息。

kafka儲存策略

kafka以topic來進行消息管理,每個topic包含多個partition,每個partition對應一個邏輯log,有多個segment組成。

每個segment中存儲多條消息(見下圖),消息id由其邏輯位置決定,即從消息id可直接定位到消息的存儲位置,避免id到位置的額外映射。

每個part在內存中對應一個index,記錄每個segment中的第一條消息偏移。

發布者發到某個topic的消息會被均勻的分布到多個partition上(或根據用戶指定的路由規則進行分布),broker收到發布消息往對應partition的最后一個segment上添加該消息,當某個segment上的消息條數達到配置值或消息發布時間超過閾值時,segment上的消息會被flush到磁盤,只有flush到磁盤上的消息訂閱者才能訂閱到,segment達到一定的大小后將不會再往該segment寫數據,broker會創建新的segment。

kafka刪除策略

1.N天前的刪除。

2.保留最近的MGB數據。

Kafka broker

與其它消息系統不同,Kafka broker是無狀態的。這意味著消費者必須維護已消費的狀態信息。這些信息由消費者自己維護,broker完全不管(有offset managerbroker管理)。

從代理刪除消息變得很棘手,因為代理并不知道消費者是否已經使用了該消息。Kafka創新性地解決了這個問題,它將一個簡單的基于時間的SLA應用于保留策略。當消息在代理中超過一定時間后,將會被自動刪除。這種創新設計有很大的好處,消費者可以故意倒回到老的偏移量再次消費數據。這違反了隊列的常見約定,但被證明是許多消費者的基本特征。

以下來自kafka官方文檔:

Kafka Design

目標

1. 高吞吐量來支持高容量的事件流處理

2.支持從離線系統加載數據

3. 低延遲的消息系統

持久化

1. 依賴文件系統,持久化到本地

2. 數據持久化到log

效率

1、 解決”small IO problem“:

使用”message set“組合消息。

server使用”chunks of messages“寫到log。

consumer一次獲取大的消息塊。

2、解決”byte copying“:

在producer、broker和consumer之間使用統一的binary message format。

使用系統的pagecache。

使用sendfile傳輸log,避免拷貝。

端到端的批量壓縮(End-to-end Batch Compression)

Kafka支持GZIP和Snappy壓縮協議。

The Producer

負載均衡

producer可以自定義發送到哪個partition的路由規則。默認路由規則:hash(key)%numPartitions,如果key為null則隨機選擇一個partition。

自定義路由:如果key是一個user id,可以把同一個user的消息發送到同一個partition,這時consumer就可以從同一個partition讀取同一個user的消息。

異步批量發送

批量發送:配置不多于固定消息數目一起發送并且等待時間小于一個固定延遲的數據。

The Consumer

consumer控制消息的讀取。

Push vs Pull

1)producer push data to broker,consumer pull data from broker

2)consumer pull的優點:consumer自己控制消息的讀取速度和數量。

3)consumer pull的缺點:如果broker沒有數據,則可能要pull多次忙等待,Kafka可以配置consumer long pull一直等到有數據。

Consumer Position

1)大部分消息系統由broker記錄哪些消息被消費了,但Kafka不是。

2)Kafka由consumer控制消息的消費,consumer甚至可以回到一個old offset的位置再次消費消息。

Message Delivery Semantics

三種:

At most once—Messages may be lost but are never redelivered.

At least once—Messages are never lost but may be redelivered.

Exactly once—this is what people actually want, each message is delivered once and only once.

Producer:有個”acks“配置可以控制接收的leader的在什么情況下就回應producer消息寫入成功。

Consumer

* 讀取消息,寫log,處理消息。如果處理消息失敗,log已經寫入,則無法再次處理失敗的消息,對應”At most once“。

* 讀取消息,處理消息,寫log。如果消息處理成功,寫log失敗,則消息會被處理兩次,對應”At least once“。

* 讀取消息,同時處理消息并把result和log同時寫入。這樣保證result和log同時更新或同時失敗,對應”Exactly once“。

Kafka默認保證at-least-once delivery,容許用戶實現at-most-once語義,exactly-once的實現取決于目的存儲系統,kafka提供了讀取offset,實現也沒有問題。

復制(Replication)

1)一個partition的復制個數(replication factor)包括這個partition的leader本身。

2)所有對partition的讀和寫都通過leader。

3)Followers通過pull獲取leader上log(message和offset)

4)如果一個follower掛掉、卡住或者同步太慢,leader會把這個follower從”in sync replicas“(ISR)列表中刪除。

5)當所有的”in sync replicas“的follower把一個消息寫入到自己的log中時,這個消息才被認為是”committed“的。

6)如果針對某個partition的所有復制節點都掛了,Kafka選擇最先復活的那個節點作為leader(這個節點不一定在ISR里)。

日志壓縮(Log Compaction)

1)針對一個topic的partition,壓縮使得Kafka至少知道每個key對應的最后一個值。

2)壓縮不會重排序消息。

3)消息的offset是不會變的。

4)消息的offset是順序的。

Distribution

Consumer Offset Tracking

1)High-level consumer記錄每個partition所消費的maximum offset,并定期commit到offset manager(broker)。

2)Simple consumer需要手動管理offset。現在的Simple consumer Java API只支持commit offset到zookeeper。

Consumers and Consumer Groups

1)consumer注冊到zookeeper

2)屬于同一個group的consumer(group id一樣)平均分配partition,每個partition只會被一個consumer消費。

3)當broker或同一個group的其他consumer的狀態發生變化的時候,consumer rebalance就會發生。

Zookeeper協調控制

1)管理broker與consumer的動態加入與離開。

2)觸發負載均衡,當broker或consumer加入或離開時會觸發負載均衡算法,使得一個consumer group內的多個consumer的訂閱負載平衡。

3)維護消費關系及每個partition的消費信息。

生產者代碼示例:

import java.util.*;

import kafka.javaapi.producer.Producer;

import kafka.producer.KeyedMessage;

import kafka.producer.ProducerConfig;

public class TestProducer {

public static void main(String[] args) {

long events = Long.parseLong(args[0]);

Random rnd = new Random();

Properties props = new Properties();

props.put("metadata.broker.list", "broker1:9092,broker2:9092 ");

props.put("serializer.class", "kafka.serializer.StringEncoder");

props.put("partitioner.class", "example.producer.SimplePartitioner");

props.put("request.required.acks", "1");

ProducerConfig config = new ProducerConfig(props);

Producer producer = new Producer(config);

for (long nEvents = 0; nEvents < events; nEvents++) {

long runtime = new Date().getTime();

String ip = “192.168.2.” + rnd.nextInt(255);

String msg = runtime + “,www.example.com,” + ip;

KeyedMessage data = new KeyedMessage("page_visits", ip, msg);

producer.send(data);

}

producer.close();

}

}

Partitioning Code:

import kafka.producer.Partitioner;

import kafka.utils.VerifiableProperties;

public class SimplePartitioner implements Partitioner {

public SimplePartitioner (VerifiableProperties props) {

}

public int partition(Object key, int a_numPartitions) {

int partition = 0;

String stringKey = (String) key;

int offset = stringKey.lastIndexOf('.');

if (offset > 0) {

partition = Integer.parseInt( stringKey.substring(offset+1)) % a_numPartitions;

}

return partition;

}

}

消費者代碼示例:

import kafka.consumer.ConsumerConfig;

import kafka.consumer.KafkaStream;

import kafka.javaapi.consumer.ConsumerConnector;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Properties;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ConsumerGroupExample {

private final ConsumerConnector consumer;

private final String topic;

private ExecutorService executor;

public ConsumerGroupExample(String a_zookeeper, String a_groupId, String a_topic) {

consumer = kafka.consumer.Consumer.createJavaConsumerConnector(

createConsumerConfig(a_zookeeper, a_groupId));

this.topic = a_topic;

}

public void shutdown() {

if (consumer != null) consumer.shutdown();

if (executor != null) executor.shutdown();

try {

if (!executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) {

System.out.println("Timed out waiting for consumer threads to shut down, exiting uncleanly");

}

} catch (InterruptedException e) {

System.out.println("Interrupted during shutdown, exiting uncleanly");

}

}

public void run(int a_numThreads) {

Map topicCountMap = new HashMap();

topicCountMap.put(topic, new Integer(a_numThreads));

Map>> consumerMap = consumer.createMessageStreams(topicCountMap);

List> streams = consumerMap.get(topic);

// now launch all the threads

//

executor = Executors.newFixedThreadPool(a_numThreads);

// now create an object to consume the messages

//

int threadNumber = 0;

for (final KafkaStream stream : streams) {

executor.submit(new ConsumerTest(stream, threadNumber));

threadNumber++;

}

}

private static ConsumerConfig createConsumerConfig(String a_zookeeper, String a_groupId) {

Properties props = new Properties();

props.put("zookeeper.connect", a_zookeeper);

props.put("group.id", a_groupId);

props.put("zookeeper.session.timeout.ms", "400");

props.put("zookeeper.sync.time.ms", "200");

props.put("auto.commit.interval.ms", "1000");

return new ConsumerConfig(props);

}

public static void main(String[] args) {

String zooKeeper = args[0];

String groupId = args[1];

String topic = args[2];

int threads = Integer.parseInt(args[3]);

ConsumerGroupExample example = new ConsumerGroupExample(zooKeeper, groupId, topic);

example.run(threads);

try {

Thread.sleep(10000);

} catch (InterruptedException ie) {

}

example.shutdown();

}

}

import kafka.consumer.ConsumerIterator;

import kafka.consumer.KafkaStream;

public class ConsumerTest implements Runnable {

private KafkaStream m_stream;

private int m_threadNumber;

public ConsumerTest(KafkaStream a_stream, int a_threadNumber) {

m_threadNumber = a_threadNumber;

m_stream = a_stream;

}

public void run() {

ConsumerIterator it = m_stream.iterator();

while (it.hasNext())

System.out.println("Thread " + m_threadNumber + ": " + new String(it.next().message()));

System.out.println("Shutting down Thread: " + m_threadNumber);

}

}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

  • Kafka入門經典教程-Kafka-about云開發 http://www.aboutyun.com/threa...
    葡萄喃喃囈語閱讀 10,863評論 4 54
  • 本文轉載自http://dataunion.org/?p=9307 背景介紹Kafka簡介Kafka是一種分布式的...
    Bottle丶Fish閱讀 5,490評論 0 34
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,829評論 18 139
  • 一、基本概念 介紹 Kafka是一個分布式的、可分區的、可復制的消息系統。它提供了普通消息系統的功能,但具有自己獨...
    ITsupuerlady閱讀 1,641評論 0 9
  • 背景介紹 Kafka簡介 Kafka是一種分布式的,基于發布/訂閱的消息系統。主要設計目標如下: 以時間復雜度為O...
    高廣超閱讀 12,866評論 8 167