Kafka中避免重複訊息的5種有效方法

banq發表於2024-03-04

Apache Kafka 因其強大的特性而成為分散式訊息系統的不錯選擇。在本文中,我們將探討避免Apache Kafka消費者中出現重複訊息的高階策略。

重複訊息消費的挑戰
Apache Kafka 的至少一次傳遞系統可確保訊息的永續性,並且可能會導致訊息被多次傳遞。在涉及網路中斷、消費者重啟或 Kafka 重新平衡的場景中,這變得尤其具有挑戰性。實施確保避免訊息重複而又不影響系統可靠性的策略至關重要。

避免重複訊息的綜合策略
以下是一些避免 Apache Kafka Consumer 中重複訊息的策略。

1. 消費者組ID和偏移量管理
確保唯一的消費者組 ID 是防止不同消費者例項之間發生衝突的基礎。此外,有效的偏移管理也很重要。在外部持久儲存系統中儲存偏移量允許消費者在發生故障時從上次成功處理的訊息恢復處理。這種做法增強了 Kafka 消費者針對重啟和重新平衡的恢復能力。

Properties properties = new Properties(); 
properties.put(<font>"bootstrap.servers"
            
"your_kafka_bootstrap_servers"); 
properties.put(
"group.id", "unique_consumer_group_id"); 

KafkaConsumer<String, String> consumer 
    = new KafkaConsumer<>(properties); 

// Manually managing offsets <i>
consumer.subscribe(Collections.singletonList(
"your_topic")); 
ConsumerRecords<String, String> records 
    = consumer.poll(Duration.ofMillis(100)); 

for (ConsumerRecord<String, String> record : records) { 
    
// Process message <i>

    
// Manually commit offset <i>
    consumer.commitSync(Collections.singletonMap( 
        new TopicPartition(record.topic(), 
                        record.partition()), 
        new OffsetAndMetadata(record.offset() + 1))); 
}

2.冪等消費者
在 Kafka 消費者中啟用冪等性提供了強大的訊息重複資料刪除機制。冪等消費者首先在 Kafka 0.11.0.0 及更高版本中引入,為每條訊息提供唯一的標識。

Properties properties = new Properties(); 
properties.put(<font>"bootstrap.servers"
            
"your_kafka_bootstrap_servers"); 
properties.put(
"group.id", "unique_consumer_group_id"); 

// Enable idempotence <i>
properties.put(
"enable.idempotence", "true"); 

KafkaConsumer<String, String> consumer 
    = new KafkaConsumer<>(properties); 

// Consume messages as usual<i>


3. 事務支援
Kafka 的事務支援是實現恰好一次語義的強大策略。透過在事務中處理訊息,消費者可以確保訊息處理和偏移量提交之間的原子性。如果出現處理錯誤,事務將回滾,從而防止偏移提交和後續訊息消耗,直到問題得到解決。

consumer.beginTransaction(); 
try
    <font>// Process message <i>
    consumer.commitTransaction(); 

catch (Exception e) { 
    
// Handle error <i>
    consumer.rollbackTransaction(); 
}

4. 死信佇列 (DLQ)
為 Kafka 消費者實現死信佇列涉及將有問題的訊息重定向到單獨的佇列以進行手動檢查。這種方法有助於隔離和分析處理失敗的訊息,使開發人員能夠在考慮重新處理之前識別並解決根本原因。

<font>// Assuming a DLQ topic named "your_topic_dlq" <i>
KafkaProducer<String, String> dlqProducer 
    = new KafkaProducer<>(dlqProperties); 

try
    
// Process message <i>
    dlqProducer.send(new ProducerRecord<>( 
        
"your_topic_dlq", record.key(), record.value())); 

catch (Exception e) { 
    
// Handle error <i>
}


5. 訊息重複資料刪除過濾器
該過濾器維護已處理訊息識別符號的記錄,允許消費者有效地識別和丟棄重複項。當嚴格的訊息排序不是關鍵要求時,這種方法特別有效。

Set<String> processedMessageIds = new HashSet<>(); 

ConsumerRecords<String, String> records 
    = consumer.poll(Duration.ofMillis(100)); 

for (ConsumerRecord<String, String> record : records) { 
    <font>// Check if the message ID has been processed <i>
    if (!processedMessageIds.contains(record.key())) { 
        
// Process message <i>

        
// Add the message ID to the set <i>
        processedMessageIds.add(record.key()); 
    } 
}


 

相關文章