Apache Kafka 程式設計實戰您可能感性的文章:
....
本章通過實際例子,講解了如何使用java進行kafka開發。
新增依賴:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.0.0</version>
</dependency>
複製程式碼
下面是建立主題的程式碼:
public class TopicProcessor {
private static final String ZK_CONNECT="localhost:2181";
private static final int SESSION_TIME_OUT=30000;
private static final int CONNECT_OUT=30000;
public static void createTopic(String topicName,int partitionNumber,int replicaNumber,Properties properties){
ZkUtils zkUtils = null;
try{
zkUtils=ZkUtils.apply(ZK_CONNECT,SESSION_TIME_OUT,CONNECT_OUT, JaasUtils.isZkSecurityEnabled());
if(!AdminUtils.topicExists(zkUtils,topicName)){
AdminUtils.createTopic(zkUtils,topicName,partitionNumber,replicaNumber,properties,AdminUtils.createTopic$default$6());
}
}catch (Exception e){
e.printStackTrace();
}finally {
zkUtils.close();
}
}
public static void main(String[] args){
createTopic("javatopic",1,1,new Properties());
}
}
複製程式碼
首先定義了zookeeper相關連線資訊。然後在createTopic中,先初始化ZkUtils,和zookeeper互動依賴於它。然後通過AdminUtils先判斷是否存在你要建立的主題,如果不存在,則通過createTopic方法進行建立。傳入引數包括主題名稱,分割槽數量,副本數量等。
生產者生產訊息
生產者生產訊息程式碼如下:
public class MessageProducer {
private static final String TOPIC="education-info";
private static final String BROKER_LIST="localhost:9092";
private static KafkaProducer<String,String> producer = null;
static{
Properties configs = initConfig();
producer = new KafkaProducer<String, String>(configs);
}
private static Properties initConfig(){
Properties properties = new Properties();
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,BROKER_LIST);
properties.put(ProducerConfig.ACKS_CONFIG,"all");
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,StringSerializer.class.getName());
return properties;
}
public static void main(String[] args){
try{
String message = "hello world";
ProducerRecord<String,String> record = new ProducerRecord<String,String>(TOPIC,message);
producer.send(record, new Callback() {
@Override
public void onCompletion(RecordMetadata metadata, Exception exception) {
if(null==exception){
System.out.println("perfect!");
}
if(null!=metadata){
System.out.print("offset:"+metadata.offset()+";partition:"+metadata.partition());
}
}
}).get();
}catch (Exception e){
e.printStackTrace();
}finally {
producer.close();
}
}
}
複製程式碼
1、首先初始化KafkaProducer物件。
producer = new KafkaProducer<String, String>(configs);
複製程式碼
2、建立要傳送的訊息物件。
ProducerRecord<String,String> record = new ProducerRecord<String,String>(TOPIC,message);
複製程式碼
3、通過producer的send方法,傳送訊息
4、傳送訊息時,可以通過回撥函式,取得訊息傳送的結果。異常發生時,對異常進行處理。
初始化producer時候,需要注意下面屬性設定:
properties.put(ProducerConfig.ACKS_CONFIG,"all");
複製程式碼
這裡有三種值可供選擇:
- 0,不等伺服器響應,直接返回傳送成功。速度最快,但是丟了訊息是無法知道的
- 1,leader副本收到訊息後返回成功
- all,所有參與的副本都複製完成後返回成功。這樣最安全,但是延遲最高。
消費者消費訊息
我們直接看程式碼
public class MessageConsumer {
private static final String TOPIC="education-info";
private static final String BROKER_LIST="localhost:9092";
private static KafkaConsumer<String,String> kafkaConsumer = null;
static {
Properties properties = initConfig();
kafkaConsumer = new KafkaConsumer<String, String>(properties);
kafkaConsumer.subscribe(Arrays.asList(TOPIC));
}
private static Properties initConfig(){
Properties properties = new Properties();
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,BROKER_LIST);
properties.put(ConsumerConfig.GROUP_ID_CONFIG,"test");
properties.put(ConsumerConfig.CLIENT_ID_CONFIG,"test");
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class.getName());
return properties;
}
public static void main(String[] args){
try{
while(true){
ConsumerRecords<String,String> records = kafkaConsumer.poll(100);
for(ConsumerRecord record:records){
try{
System.out.println(record.value());
}catch(Exception e){
e.printStackTrace();
}
}
}
}catch(Exception e){
e.printStackTrace();
}finally {
kafkaConsumer.close();
}
}
}
複製程式碼
程式碼邏輯如下:
1、初始化消費者KafkaConsumer,並訂閱主題。
kafkaConsumer = new KafkaConsumer<String, String>(properties);
kafkaConsumer.subscribe(Arrays.asList(TOPIC));
複製程式碼
2、迴圈拉取訊息
ConsumerRecords<String,String> records = kafkaConsumer.poll(100);
複製程式碼
poll方法傳入的引數100,是等待broker返回資料的時間,如果超過100ms沒有響應,則不再等待。
3、拉取回訊息後,迴圈處理。
for(ConsumerRecord record:records){
try{
System.out.println(record.value());
}catch(Exception e){
e.printStackTrace();
}
}
複製程式碼
消費相關程式碼比較簡單,不過這個版本沒有處理偏移量提交。學習過第四章-協調器相關的同學應該還記得偏移量提交的問題。我曾說過最佳實踐是同步和非同步提交相結合,同時在特定的時間點,比如再均衡前進行手動提交。
加入偏移量提交,需要做如下修改:
1、enable.auto.commit設定為false
2、消費程式碼如下:
public static void main(String[] args){
try{
while(true){
ConsumerRecords<String,String> records =
kafkaConsumer.poll(100);
for(ConsumerRecord record:records){
try{
System.out.println(record.value());
}catch(Exception e){
e.printStackTrace();
}
}
kafkaConsumer.commitAsync();
}
}catch(Exception e){
e.printStackTrace();
}finally {
try{
kafkaConsumer.commitSync();
}finally {
kafkaConsumer.close();
}
}
}
複製程式碼
3、訂閱訊息時,實現再均衡的回撥方法,在此方法中手動提交偏移量
kafkaConsumer.subscribe(Arrays.asList(TOPIC), new ConsumerRebalanceListener() {
@Override
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
//再均衡之前和消費者停止讀取訊息之後呼叫
kafkaConsumer.commitSync(currentOffsets);
}
});
複製程式碼
通過以上三步,我們把自動提交偏移量改為了手動提交。正常消費時,非同步提交kafkaConsumer.commitAsync()。即使偶爾失敗,也會被後續成功的提交覆蓋掉。而在發生異常的時候,手動提交 kafkaConsumer.commitSync()。此外在步驟3中,我們通過實現再均衡時的回撥方法,手動同步提交偏移量,確保了再均衡前偏移量提交成功。
以上面的最佳實踐提交偏移量,既能保證消費時較高的效率,又能夠儘量避免重複消費。不過由於重複消費無法100%避免,消費邏輯需要自己處理重複消費的判斷。
更多你可能感興趣的文章:
1-Flink入門
2-本地環境搭建&構建第一個Flink應用
3-DataSet API
4-DataSteam API
5-叢集部署
6-分散式快取
7-重啟策略
8-Flink中的視窗
9-Flink中的Time
Flink時間戳和水印
Broadcast廣播變數
FlinkTable&SQL
Flink實戰專案實時熱銷排行
Flink寫入RedisSink
Flink消費Kafka寫入Mysql
Flink元件和邏輯計劃
Flink執行計劃生成
JobManager中的基本元件(1)
JobManager中的基本元件(2)
JobManager中的基本元件(3)
TaskManager
運算元
網路
水印WaterMark
CheckPoint
任務排程與負載均衡
異常處理
Alibaba Blink新特性
Java高階特性增強-集合
Java高階特性增強-多執行緒
Java高階特性增強-Synchronized
Java高階特性增強-volatile
Java高階特性增強-併發集合框架
Java高階特性增強-分散式
Java高階特性增強-Zookeeper
Java高階特性增強-JVM
Java高階特性增強-NIO
Java高階特性增強-Netty
你真的不關注一下嘛~