目錄
1 Kafka入門
1.1 主流mq框架對比
ActiveMQ | RabbitMQ | Kafka | |
---|---|---|---|
吞吐量 | 1w | 1w | 10w |
支持的協議 | OpenMessage, AMQP, MQTT, STOMP | AMQP | 仿AMQP |
事務 | 支持 | 支持 | 支持 |
集羣 | 支持(不良好) | 支持(不良好) | 支持 |
負載均衡 | 支持 | 支持 | 支持 |
動態擴展 | 不支持 | 不支持 | 支持 |
編寫語言 | Java | Erlang | Scala |
這三個MQ組件中, ActiveMQ的功能最豐富, 支持的協議最多。 吞吐量上, 一般情況下Kafka > RabbitMQ > ActiveMQ; 可靠性上, 一般情況下RabbitMQ > ActiveMQ > Kafka。
動態擴展, 是指可以向運行中的集羣添加新的節點, 而不影響已有節點的使用。 之所以說ActiveMQ對集羣的支持不良好, 其中一個原因是 ActiveMQ的節點只能是主從模式, 只有再master節點上纔可以發佈和消費消息, 這樣的話對併發量的提升相對較弱。
1.2 kafka主要特性
消息系統: 可以發佈和訂閱消息, 類似於消息隊列或企業級消息系統。
存儲: 提供容錯的方式來存儲流數據。 存儲在kafka中的數據, 都會落到磁盤上, 只要不手動刪除, 將一直存在, 不像其他消息中間件, 當消息消費後, 會對消息進行刪除。
流處理: 可以在一個流的數據產生時, 就對它進行處理, 即流處理。這個特性是kafka的streams api來支持的,需要在客戶端上編碼, 實質上是讀取現有的流數據, 將處理的結果推到結果的流上。 但主流的還是採用fink, storm sreams, spark等批處理框架來進行流處理。 kafka更多的是充當一個流數據的存儲角色。
總的來說, Kafka不僅僅是一個消息系統, 還是一個數據存儲。
1.3 AMQP協議
AMQP是由金融業的摩根大通公司主導制定的消息協議, 是一個應用層的協議。
在Kafka中, 生產者push,消費者poll,都是客戶端主動發起數據請求。kafka都是以多個broker集羣的方式對外提供服務。
1.4 Kafka整體架構
1.5 核心概念
broker
一個Kafka示例, 一般情況下, Kafka都是以集羣的方式部署的。
topic
消息的一種分類, 一個主題的消息可以視爲一個數據流。主題中的消息不一定按照發布的順序消費。
partition
一個主題可以分爲多個partition,每一個partition都是順序存儲在磁盤的。 每個partition的消息有自己的id, 對於消費者, partion有自己對應的commit offset。partition的意義: 其一, 如果通過將一個主題分隔成多個partition, 部署到多個broker上來提升io的速度, 甚至通過這種方式, 獲得和內存相近的吞吐量; 其二, partition可以分佈在多個broker上, 可以避免一次性丟失所有數據的情況。
partition中的消息是會按照發布的順序消費的。
record
每條記錄都有key, value和timestamp三個數據。 其中具有相同key的消息, 可以保證落到同一個partition中。
replication
每一個partition可以有多個副本, 副本分佈在不同的broker上, 通過這種冗餘, 可以保證數據的安全性, 只要不是所有的副本都丟失, 那麼partition中的數據就是安全的。 副本的數量(replication-factor)不能超過broker的數量, 因爲將同樣的副本存在同一臺機器上, 對於數據安全性,沒有作用。
replication有一下的特性:
- 同一個partition的多個replication不允許在同一個broker中;(在配置中, replication-factor不能超過broker的數量)
- 同一個parition的多個replication中, 有一個leader, 0個或多個follower;
- 消息的讀寫只能發生在leader節點上, follower只是被動的複製;
- 當leader節點宕機時, 集羣會選舉出新的leader節點;
注意: 這裏的leader和follower是replication級別的, Kafka的broker節點之間沒有主次之分, 它們是完全同等的。
1.6 kafaka 核心API
概述
- producer, 向topic發佈消息的應用。
- consumer, 從broker中接收消息, 進行處理的應用。
- streams api, 一個流處理的api, 從一個或多個主題接收消息,進行處理後, 將處理結果放到一個或多個主題中。
- connector, 可重用的producer或consumer。 用於將已有系統, 如數據庫等的數據集成到kafka上。
這四種API, 用來構建四種類型的Kafka客戶端, 如下:
producer
使用代碼示例:
// 設置producer的配置
Properties settings = new Properties();
settings.put("batch.size", 16 * 1024); // 緩衝區大小, 默認16k
settings.put("linger.ms", 1000); // 發送前, 等待的時間, 默認爲0
settings.put("acks", "all"); // 多少個broker 確認才認爲成功。 0,
settings.put("retries", 1 ); // 重試的次數
....
Producer<String, String> producer = new KafkaProducer(settings);
// 發送消息
ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key", "value");
producer.send(record);
producer.close();
producer發送消息時, 並不是直接發送到broker中的, 而是先放在本地內存中的一個緩衝區,當緩衝區大小達到最大大小或緩衝區中的消息達到停留時間時, 才進行發送。 如下:
producer有三個重要的配置:
- batch.size: 緩衝區大小, 默認16k
- linger.ms: 發送前, 等待的時間, 默認爲0
- acks: 多少個broker 確認才認爲消息發佈成功, 可選值爲0, 1, all。 0, 是發送之後就認爲是成功了, 不去考慮這個消息是否交付到kafka中; 1, 當leader節點確認成功, 就認爲已經成功的交付到kafka中了, 這種情況下, 如果leader節點宕機, 而又沒有來得即將消息同步到follower上, 那麼就會出現消息丟失; all, 只有當所有的broker都ack之後, 才認爲一個消息發送成功。
一旦達到batch.size或linger.ms其中一個條件, 緩衝區的消息就會被立刻發送。
consumer
1 simple consumer API
每次消費消息時, 都需要提供topic, partition, offset, feichSize等四個參數, 不提供負載均衡和容錯的特性。
非常基礎, 但是基於可以定義實現所有的功能。
2 high level consumer API
消費時只需要指定topic, 客戶端透明地切換consumer的partition, 實現consumer group級別的負載均衡。 如下圖:
consumer group有如下的特性:
- 一個topic可以有多個consumer group, 每一個consumer group都可以接收到所有的topic中的數據。
- consumer group中可以有一個或多個consumer, 每個consumer處理主題中的一個或多個partition。
- 一個group中的一個partition只能被一個consumer處理。
可以通過consumer group來實現隊列和廣播:
- 隊列: 當所有的消費者都在一個group中時, 那麼每個消息都只會被消費一次。
- 廣播(主題): 當所有的消費者都分屬不同的消費者, 那麼每個消費者都會接收到topic中的所有消息。
consumer 什麼時候會退出group?
- consumer在很長的一段時間內沒有心跳時;
- 當consumer很久沒有poll數據時;
3 consumer的commit offset
consumer可以通過commit, 來告訴服務器, 當前已經消費了的消息, 當consumer因爲某種原因重啓時, 會從最新提交的offset的下一個消息開始消費。 默認的情況下, Consumer是自動提交的, 每當poll數據時, 就會提交上一條數據。
除了這個存在kafka的commit offset, 還有一個consumer自己持有的offset, 來指向下一個消息。
4 consumer的數據獲取方式
kafka中,消費者是隻能通過主動poll的方式來獲取數據的。
push和poll兩種方式的難點:
- push, 難點是請求的壓力可能落到consumer上: 消息隊列可能無法起到緩衝區的作用, 無法進行削峯(這是在消息中間件服務端完全不做控制的情況);
- poll, 難點是poll時間間隔的取捨, 隔一段時間去獲取一次數據, 這個時間的間隔如果太短, 服務器的壓力就會比較大, 如果過小, 那麼數據就不夠實時;
poll時間間隔的解決方案--- long polling:
consumer poll數據時, 如果當前數據不夠, 那麼這個poll請求會阻塞, 等待有足夠多的數據或者到達等待時間時才返回。
2 kafka使用場景
2.1 消息系統
原因: 高可用; 根據經驗, 通常對消息傳遞對吞吐量的要求比較低, 但是要求較低的端到端延遲, 並且要有可靠的durable機制(kafka是一個持久化的消息隊列);高吞吐量;
對於消息順序的保證, 從某種角度來說, kafka會比較好。因爲即使是RabbitMQ和ActiveMQ, 當有多個消費者進行消費時, 其實我們沒有辦法保證哪個消費者先消費完, 其實順序也會丟失。
kafka實現順序消費的方法:
- 使用相同的key, 讓消息只發送到一個partition中, 而一個partition只會被消費者組內的一個消費者所使用;
- topic內只有一個消費者;
2.2 存儲系統
高性能, 低延遲, 高可用的日誌提交存儲。
2.3 日誌聚合
日誌處理的流程: 收集, 清洗(一般是使用正則來清洗), 聚合,存儲, 展示
可能不能作爲一個完全的日誌解決方案, ELK的日誌解決方案更加有優勢。 (ELK的缺點: 聚合節點Logstash可能會成爲系統瓶頸)
爲什麼要進行日誌的聚合?
如果是分佈式系統, 那麼一個程序的多個實例的日誌需要進行聚合。 一個請求在上下游的日誌也需要聚合。
2.4 跟蹤網站活動(其實就是埋點)
kafka在LinkedIn中就因此而生。
2.5 流處理
Kafka StreamAPIs 可以進行流處理, 但是如果要使用複雜的流處理功能, 還是使用flink, spark streaming等框架。
爲什麼需要流處理?
和流處理相對的是批處理, 批處理有很大的延遲, 比如說前一天去跑一些統計數據。 而流處理, 是一有新的數據就馬上計算更新結果的處理方式。