Kafka 發送消息過程中攔截器的用途?

消息在通過 send() 方法發往 broker 的過程中,有可能需要經過攔截、序列化器 和 分區器 的一系列作用之後才能被真正地發往 broker。

攔截器是早在 Kafka 0.10.0.0 中就已經引入的一個功能,Kafka 一共有兩種攔截器:生產者攔截器和消費者攔截器。這裏主要講述生產者攔截器的相關內容

生產者攔截器既可以用來在消息發送前做一些準備工作,比如按照某個規則過濾不符合要求的消息、修改消息的內容等,也可以用來在發送回調邏輯前做一些定製化的需求,比如統計類工作。

生產者攔截器的使用也很方便,主要是自定義實現 org.apache.kafka.clients.producer. ProducerInterceptor 接口。ProducerInterceptor 接口中包含3個方法:

KafkaProducer 在將消息序列化和計算分區之前會調用生產者攔截器的onSend() 方法來對消息進行相應的定製化操作。一般來說最好不要修改消息 ProducerRecord 的 topic、key 和 partition 等信息,如果要修改,則需確保對其有準確的判斷,否則會與預想的效果出現偏差。比如修改 key 不僅會影響分區的計算,同樣會影響 broker 端日誌壓縮(Log Compaction)的功能。

KafkaProducer 會在消息被應答(Acknowledgement)之前或消息發送失敗時調用生產者攔截器的 onAcknowledgement() 方法,優先於用戶設定的 Callback 之前執行。這個方法運行在 Producer 的I/O線程中,所以這個方法中實現的代碼邏輯越簡單越好,否則會影響消息的發送速度。

close() 方法主要用於在關閉攔截器時執行一些資源的清理工作。在這3個方法中拋出的異常都會被捕獲並記錄到日誌中,但並不會再向上傳遞。

ProducerInterceptor 接口與 Partitioner 接口一樣,它也有一個同樣的父接口 Configurable,具體的內容可以參見 Partitioner 接口的相關介紹。

下面通過一個示例來演示生產者攔截器的具體用法,ProducerInterceptorPrefix 中通過 onSend() 方法來爲每條消息添加一個前綴“prefix1-”,並且通過 onAcknowledgement() 方法來計算髮送消息的成功率。ProducerInterceptorPrefix 類的具體實現如代碼

實現自定義的 ProducerInterceptorPrefix 之後,需要在 KafkaProducer 的配置參數 interceptor.classes 中指定這個攔截器,此參數的默認值爲“”。示例如下:

然後使用指定了 ProducerInterceptorPrefix 的生產者連續發送10條內容爲“kafka”的消息,在發送完之後客戶端打印出如下信息:

如果消費這10條消息,會發現消費了的消息都變成了“prefix1-kafka”,而不是原來的“kafka”。

KafkaProducer 中不僅可以指定一個攔截器,還可以指定多個攔截器以形成攔截鏈。攔截鏈會按照 interceptor.classes 參數配置的攔截器的順序來一一執行(配置的時候,各個攔截器之間使用逗號隔開)。下面我們再添加一個自定義攔截器 ProducerInterceptorPrefixPlus,它只實現了 Interceptor 接口中的 onSend() 方法,主要用來爲每條消息添加另一個前綴“prefix2-”,具體實現如下:





此時生產者再連續發送10條內容爲“kafka”的消息,那麼最終消費者消費到的是10條內容爲“prefix2-prefix1-kafka”的消息。如果將 interceptor.classes 配置中的兩個攔截器的位置互換:

那麼最終消費者消費到的消息爲“prefix1-prefix2-kafka”。



如果攔截鏈中的某個攔截器的執行需要依賴於前一個攔截器的輸出,那麼就有可能產生“副作用”。設想一下,如果前一個攔截器由於異常而執行失敗,那麼這個攔截器也就跟着無法繼續執行。在攔截鏈中,如果某個攔截器執行失敗,那麼下一個攔截器會接着從上一個執行成功的攔截器繼續執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章