開心一刻
今天小學女同學給我發訊息
她:你現在是畢業了嗎
我:嗯,今年剛畢業
她給我發了一張照片,懷裡抱著一隻大橘貓
她:我的眯眯長這麼大了,好看嗎
我:你把貓挪開點,它擋住了,我看不到
她:你是 sb 嗎,滾
我解釋道:你說的是貓呀
可訊息剛發出,就出現了紅色感嘆號,並提示:訊息已發出,但被對方拒收了
kafka搭建
出於簡單考慮,基於 docker
搭建一個 kafka
節點;因為一些原因,國內的 Docker Hub 映象加速器都不可用了,目前比較靠譜的做法是搭建個人映象倉庫,可參考:Docker無法拉取映象解決辦法,我已經試過了,是可行的,但還是想補充幾點
-
sync-image-example.yml
只需要修改最後的映象複製,其他內容不需要改支援一次配置多個映象的複製
-
映象複製
docker 映象複製命令的格式
skopeo copy docker://docker.io/名稱空間/映象名:TAG docker://阿里雲映象地址/名稱空間/映象名:TAG
我們以 kafka 為例,去 Docker Hub 一搜,好傢伙,搜出來上萬個
我們將搜尋條件精確化一些,搜
wurstmeister/kafka
點進去,它在 Docker Hub 的地址是:
https://hub.docker.com/r/wurstmeister/kafka
那它的 docker 地址就是
docker://docker.io/wurstmeister/kafka
其他的映象用類似的方式去找,所以最終的複製命令類似如下:
skopeo copy docker://docker.io/wurstmeister/kafka:latest docker://registry.cn-hangzhou.aliyuncs.com/qingshilu/wurstmeister_kafka:latest
如果一切順利,那麼在我們的阿里雲個人映象倉庫就能看到我們複製的映象了
-
如何 pull
在個人倉庫點映象名,會看到
操作指南
我們只關注前兩步,就可以將映象 pull 下來
映象獲取到之後,就可以搭建 kafka
了;因為依賴 zookeeper
,我們先啟動它
docker run -d --name zookeeper-test -p 2181:2181 \
--env ZOO_MY_ID=1 \
-v zookeeper_vol:/data \
-v zookeeper_vol:/datalog \
-v zookeeper_vol:/logs \
registry.cn-hangzhou.aliyuncs.com/qingshilu/wurstmeister_zookeeper
然後啟動 kafka
docker run -d --name kafka-test -p 9092:9092 \
--env KAFKA_ZOOKEEPER_CONNECT=192.168.2.118:2181 \
--env KAFKA_ADVERTISED_HOST_NAME=192.168.2.118 \
--env KAFKA_ADVERTISED_PORT=9092 \
--env KAFKA_LOG_DIRS=/kafka/logs \
-v kafka_vol:/kafka \
registry.cn-hangzhou.aliyuncs.com/qingshilu/wurstmeister_kafka
不出意外的話,都啟動成功
如果出意外了,大家也別慌,用 docker log
去檢視日誌,然後找對應的解決方案
# 1.先找到啟動失敗的容器id
docker ps -a
# 2.用 docker log 檢視容器啟動日誌
docker log 容器id
如果需要開啟 kafka
的 SASL
認證,可參考:Docker-Compose搭建帶SASL使用者密碼驗證的Kafka 來搭建
Kafka Tool
詳情可檢視:kafka視覺化客戶端工具(Kafka Tool)的基本使用
建立 Topic:test-topic
,併傳送一條訊息
此時 test-topic
中有 1 條訊息
消費者 poll
程式碼很簡單
/**
* @author: 青石路
*/
public class MsgConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(MsgConsumer.class);
public static void main(String[] args) {
Properties props = new Properties();
props.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.2.118:9092");
props.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "test_group");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
// 如果在kafka中找不到當前消費者的偏移量,則設定為最舊的
props.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 500);
KafkaConsumer<String, String> consumer = new KafkaConsumer<String,String>(props);
// 訂閱主題
consumer.subscribe(Collections.singleton("test-topic"));
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
LOGGER.info("records count = {}", records.count());
records.forEach(record -> LOGGER.info("{} - {} - {}", record.offset(), record.key(), record.value()));
// consumer.commitAsync();
consumer.close();
}
}
我們執行下,輸出日誌如下
竟然 poll 不到訊息,為什麼呀?
我們調整下程式碼,迴圈 poll
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
LOGGER.info("records count = {}", records.count());
records.forEach(record -> LOGGER.info("{} - {} - {}", record.offset(), record.key(), record.value()));
}
我們再執行下,輸出日誌如下
消費者 poll 的過程中會先判斷當前消費者是否在 消費者組
中,如果不在,會先加入消費者組,在加入過程中,ConsumerCoordinator
會對這個消費者組 Rebalance,整個過程中該消費者組內的所有消費者都不能工作,而 poll 又配置了超時時間(100 毫秒
),如果在超時時間內,當前消費者還未正常加入消費者組中,那麼 poll 肯定是拉取不到資料的;根據日誌可以看出,第 3 次 poll 的時候,消費者已經正常加入消費者組中,那麼就能 poll 到資料了
很多小夥伴可能可能會有這樣的疑問
平時在專案中使用的時候,從來沒有感受到這樣的問題,為什麼呢
原因有以下幾點
- poll 的超時時間設定比較長,超時時間內消費者能夠正常加入到消費者組中
- 消費者隨專案的啟動建立,存活週期與專案一致,那麼只有前幾次 poll 的時候,可能會因為消費者未加入到消費者組中而拉取不到資料,而一旦消費者成功加入到消費者組之後,那麼只要 Topic 中有資料,poll 肯定能拉取到資料;從整個次數佔比來看,poll 拉取不到資料的異常情況(Topic 中有可拉取的資料,但 poll 不到)佔比非常小,小到可以忽略不計了
所以你們感受不到這樣;但如果某些場景下,比如 DataX 從 kafka 讀資料
異源資料同步 → DataX 為什麼要支援 kafka?
消費者要不斷新建,那麼 poll 不到資料的異常情況的佔比就會上來了,那就需要透過一些機制來降低其所造成的的影響了,比如說重試機制
總結
- 示例程式碼:kafka-demo
- 如果大家平時用 docker 比較多,推薦透過搭建個人映象倉庫來解決映象拉取超時的問題
- kakfa 消費者 poll 的時候,消費者如果不在消費者組中,會先加入消費者組,那麼超時時間內可能 poll 不到資料,可以透過增大超時時間,或者重試機制來降低 poll 不到資料的異常次數(Topic 中沒有可拉取的資料而 poll 不到的情況不算異常情況)