關于Kafka ACK機制的詳解!
Kafka的 ACK機制是確保消息成功傳遞和處理的重要機制.這篇文章,我們將詳細分析 Kafka ACK機制,包括其原理、源碼分析、使用場景以及優缺點。
ACK 方式
Kafka的 ACK機制主要用于確保生產者發送的消息能夠被可靠地寫入到 Kafka集群的 Topic中。ACK機制的核心思想是生產者發送消息后,需要等待 Kafka集群的確認(ACK),才認為消息發送成功。
Kafka的 ACK機制主要有三種級別:
1.acks=0
生產者不等待服務器的確認,消息發送后即認為成功,不管消息是否真正寫入 Kafka,這種方式效率最高,但可靠性最低,數據可能存在丟失。
2.acks=1
生產者會等待來自 Leader分區的確認。Leader分區接收到消息并寫入本地日志后即返回確認。這種方式在 Leader分區可用時可靠,但如果 Leader分區發生故障,可能會丟失數據。從 Kafka 2.0 開始,默認值是 acks=1
3.acks=all(或-1)
生產者等待所有 ISR(In-Sync Replica,同步副本)分區的確認。只有當消息被寫入所有同步副本后才返回確認,這種方式最可靠,但性能較低。
ISR的工作原理
ISR,全稱 In-Sync Replicas,翻譯為同步副本,它是指某個分區中的一組與 Leader副本保持同步的副本,即這些副本包含了 Leader副本中的所有已確認消息。ISR是 Kafka 集群中用于保證數據可靠性的一個關鍵概念。
- Leader和 Follower:在 Kafka中,每個分區都有一個 Leader和若干個 Follower,Leader負責處理所有的讀寫請求,而 Follower則從 Leader那里拉取數據并進行同步。
- 同步副本(ISR):ISR是一個動態的集合,包含了 Leader和所有與 Leader保持同步的 Follower,只有在 ISR中的副本才被認為是可靠的,因為它們包含了與 Leader相同的數據。
- ACK機制與 ISR:當生產者發送消息并設置acks=all時,Kafka只有在消息被寫入 ISR中的所有副本后才會返回確認,這確保了消息即使在 Leader故障的情況下也不會丟失,因為 ISR中的其他副本可以選舉為新的 Leader。
1.ISR的維護
Kafka通過以下機制來維護ISR:
- 加入ISR:當一個 Follower副本成功地追上了 Leader副本的日志(即復制了 Leader的所有新的消息),它會被加入到 ISR中。
- 移出ISR:當一個 Follower副本落后于 Leader超過一定的時間(由參數replica.lag.time.max.ms控制),它會被移出 ISR。
2.ISR源碼分析
以下是 Kafka中維護ISR的關鍵代碼片段(以 Kafka 2.x版本為例):
class Partition {
private Set<Replica> isr; // 當前分區的ISR集合
public void updateISR() {
// 獲取所有副本的狀態
List<Replica> replicas = getReplicas();
// 計算新的ISR集合
Set<Replica> newIsr = new HashSet<>();
for (Replica replica : replicas) {
if (replica.isInSync()) {
newIsr.add(replica);
}
}
// 更新ISR
if (!newIsr.equals(this.isr)) {
this.isr = newIsr;
// 觸發ISR變化的事件
onISRChanged();
}
}
}
class Replica {
public boolean isInSync() {
// 判斷該副本是否與Leader同步
return this.logEndOffset >= leaderLogEndOffset - replicaLagMaxMessages;
}
}
源碼分析
以 Kafka的 Producer端代碼為例,下面是簡化后的發送消息時處理ACK機制的關鍵代碼片段:
public Future<RecordMetadata> send(ProducerRecord<K, V> record, Callback callback) {
// 構建請求
ProduceRequest request = new ProduceRequest(record, callback);
// 發送請求
Future<RecordMetadata> future = this.sender.send(request);
// 根據ACK配置處理確認
if (this.acks == 0) {
// 不等待確認,直接返回成功
callback.onCompletion(null, null);
} else if (this.acks == 1) {
// 等待Leader確認
RecordMetadata metadata = future.get();
callback.onCompletion(metadata, null);
} else if (this.acks == -1 || this.acks == "all") {
// 等待所有ISR確認
RecordMetadata metadata = future.get();
callback.onCompletion(metadata, null);
}
return future;
}
優缺點
acks=0:
- 優點:性能最高,延遲最低。
- 缺點:消息可能丟失,可靠性最低。
acks=1:
- 優點:在性能和可靠性之間取得平衡。
- 缺點:如果領導者在消息寫入后但未同步給副本前崩潰,消息可能丟失。
acks=all:
- 優點:最高的可靠性,確保消息被所有同步副本確認。
- 缺點:性能較低,延遲較高。
缺點:
- 性能影響:更高的ACK級別會帶來更高的延遲,降低吞吐量。
- 復雜性:需要根據具體應用場景選擇合適的ACK配置,增加了系統設計的復雜性。
適用場景
- acks=0:適用于對消息丟失不敏感且追求高吞吐量的場景,例如日志收集、監控數據等。
- acks=1:適用于對消息有一定可靠性要求,但對性能要求較高的場景,例如實時數據處理。
- acks=all:適用于對消息可靠性要求極高且可以接受較低吞吐量的場景,例如金融交易、訂單處理等。
總結
本文我們分析了 Kafka的 ACK機制以及 ISR機制,從全局來看, Kafka 和 RocketMQ有著異曲同工之妙,Kafka的 ack=all 對應 RocketMQ的同步發送,ack=1 對應 RocketMQ的異步發送,ack=0 對應 RocketMQ的單向發送。
總體來說,Kafka的 ACK機制為消息的可靠傳遞提供了不同級別的保障,開發者可以根據具體的應用需求選擇合適的 ACK配置,以在性能和可靠性之間取得平衡。