史上最差的kafka教程第三天(简单案例代码)
导入依赖
<dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.4.0</version> </dependency> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-streams</artifactId> <version>2.4.0</version> </dependency>
kafka配置类
/** * @ClassName * @Description TODO * @AUTHOR admin * @DATE 2020/6/29 17:35 */ @Configuration @EnableKafka public class KafkaConfiguration { //ConcurrentKafkaListenerContainerFactory为创建Kafka监听器的工程类,这里只配置了消费者 @Bean public ConcurrentKafkaListenerContainerFactory<Integer, String> kafkaListenerContainerFactory() { ConcurrentKafkaListenerContainerFactory<Integer, String> factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(consumerFactory()); return factory; } //根据consumerProps填写的参数创建消费者工厂 @Bean public ConsumerFactory<Integer, String> consumerFactory() { return new DefaultKafkaConsumerFactory<>(consumerProps()); } //根据senderProps填写的参数创建生产者工厂 @Bean public ProducerFactory<Integer, String> producerFactory() { return new DefaultKafkaProducerFactory<>(senderProps()); } //kafkaTemplate实现了Kafka发送接收等功能 @Bean public KafkaTemplate<Integer, String> kafkaTemplate() { KafkaTemplate template = new KafkaTemplate<Integer, String>(producerFactory()); return template; } //消费者配置参数 private Map<String, Object> consumerProps() { Map<String, Object> props = new HashMap<>(); //连接地址 props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092"); //GroupID props.put(ConsumerConfig.GROUP_ID_CONFIG, "bootKafka"); //是否自动提交 props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true); //自动提交的频率 props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000"); //Session超时设置 props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000"); //键的反序列化方式 props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class); //值的反序列化方式 props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); return props; } //生产者配置 private Map<String, Object> senderProps (){ Map<String, Object> props = new HashMap<>(); //连接地址 props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.137.4:9092"); //重试,0为不启用重试机制 props.put(ProducerConfig.RETRIES_CONFIG, 1); //控制批处理大小,单位为字节 props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384); //批量发送,延迟为1毫秒,启用该功能能有效减少生产者发送消息次数,从而提高并发量 props.put(ProducerConfig.LINGER_MS_CONFIG, 1); //生产者可以使用的总内存字节来缓冲等待发送到服务器的记录 props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 1024000); //键的序列化方式 props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class); //值的序列化方式 props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); return props; } }
生产者示例代码
public class ProducerSample {
/* Producer异步发送带回调函数和Partition负载均衡 */ public static void producerSendWithCallbackAndPartition(){ Properties properties = new Properties(); // properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.220.128:9092"); properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"127.0.0.1:9092"); properties.put(ProducerConfig.ACKS_CONFIG,"all"); properties.put(ProducerConfig.RETRIES_CONFIG,"0"); properties.put(ProducerConfig.BATCH_SIZE_CONFIG,"16384"); properties.put(ProducerConfig.LINGER_MS_CONFIG,"1"); properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG,"33554432"); properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG,"com.sun4cloud.sunx.kafka.producer.SamplePartition"); // Producer的主对象 Producer<String,String> producer = new KafkaProducer<>(properties); // 消息对象 - ProducerRecoder for(int i=0;i<5;i++){ ProducerRecord<String,String> record = new ProducerRecord<>(TOPIC_NAME,"key-"+i,"value-"+i); producer.send(record, new Callback() { @Override public void onCompletion(RecordMetadata recordMetadata, Exception e) { System.out.println( "partition : "+recordMetadata.partition()+" , offset : "+recordMetadata.offset()); } }); } // 所有的通道打开都需要关闭 producer.close(); } /* Producer异步发送带回调函数 */ public static void producerSendWithCallback(){ Properties properties = new Properties(); properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"127.0.0.1:32649"); properties.put(ProducerConfig.ACKS_CONFIG,"all"); properties.put(ProducerConfig.RETRIES_CONFIG,"0"); properties.put(ProducerConfig.BATCH_SIZE_CONFIG,"16384"); properties.put(ProducerConfig.LINGER_MS_CONFIG,"1"); properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG,"33554432"); properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); // Producer的主对象 Producer<String,String> producer = new KafkaProducer<>(properties); // 消息对象 - ProducerRecoder for(int i=0;i<10;i++){ ProducerRecord<String,String> record = new ProducerRecord<>(TOPIC_NAME,"key-"+i,"value-"+i); producer.send(record, new Callback() { @Override public void onCompletion(RecordMetadata recordMetadata, Exception e) { System.out.println( "partition : "+recordMetadata.partition()+" , offset : "+recordMetadata.offset()); } }); } // 所有的通道打开都需要关闭 producer.close(); } /* Producer异步发送演示 */ public static void producerSend(){ Properties properties = new Properties(); properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"127.0.0.1:9092"); properties.put(ProducerConfig.ACKS_CONFIG,"all"); properties.put(ProducerConfig.RETRIES_CONFIG,"0"); properties.put(ProducerConfig.BATCH_SIZE_CONFIG,"16384"); properties.put(ProducerConfig.LINGER_MS_CONFIG,"1"); properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG,"33554432"); properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); // Producer的主对象 Producer<String,String> producer = new KafkaProducer<>(properties); // 消息对象 - ProducerRecoder for(int i=0;i<10;i++){ ProducerRecord<String,String> record = new ProducerRecord<>(TOPIC_NAME,"key-"+i,"value-"+i); producer.send(record); } // 所有的通道打开都需要关闭 producer.close(); } /* Producer异步阻塞发送 */ public static void producerSyncSend() throws ExecutionException, InterruptedException { Properties properties = new Properties(); properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.220.128:9092"); properties.put(ProducerConfig.ACKS_CONFIG,"all"); properties.put(ProducerConfig.RETRIES_CONFIG,"0"); properties.put(ProducerConfig.BATCH_SIZE_CONFIG,"16384"); properties.put(ProducerConfig.LINGER_MS_CONFIG,"1"); properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG,"33554432"); properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); // Producer的主对象 Producer<String,String> producer = new KafkaProducer<>(properties); // 消息对象 - ProducerRecoder for(int i=0;i<10;i++){ String key = "key-"+i; ProducerRecord<String,String> record = new ProducerRecord<>(TOPIC_NAME,key,"value-"+i); Future<RecordMetadata> send = producer.send(record); RecordMetadata recordMetadata = send.get(); System.out.println(key + "partition : "+recordMetadata.partition()+" , offset : "+recordMetadata.offset()); } // 所有的通道打开都需要关闭 producer.close(); }
分区策略
public class SamplePartition implements Partitioner {
@Override
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
// String keyStr = key + "";
// String keyInt = keyStr.substring(4);
List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
System.out.println("keyStr : "+keyStr + "keyInt : "+keyInt);
return Math.abs(key.hashCode()) % partitions.size();
// int i = Integer.parseInt(keyInt);
return i%2;
}
@Override
public void close() {
}
@Override
public void configure(Map<String, ?> configs) {
}
}
public class ConsumerSample {/* 工作里这种用法,有,但是不推荐 */ private static void helloworld(){ Properties props = new Properties(); props.setProperty("bootstrap.servers", "192.168.220.128:9092"); props.setProperty("group.id", "test"); props.setProperty("enable.auto.commit", "true"); props.setProperty("auto.commit.interval.ms", "1000"); props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String,String> consumer = new KafkaConsumer(props); // 消费订阅哪一个Topic或者几个Topic consumer.subscribe(Arrays.asList(TOPIC_NAME)); while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(10000)); for (ConsumerRecord<String, String> record : records) System.out.printf("patition = %d , offset = %d, key = %s, value = %s%n", record.partition(),record.offset(), record.key(), record.value()); } } /* 手动提交offset */ private static void commitedOffset() { Properties props = new Properties(); props.setProperty("bootstrap.servers", "192.168.220.128:9092"); props.setProperty("group.id", "test"); props.setProperty("enable.auto.commit", "false"); props.setProperty("auto.commit.interval.ms", "1000"); props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer(props); // 消费订阅哪一个Topic或者几个Topic consumer.subscribe(Arrays.asList(TOPIC_NAME)); while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(10000)); for (ConsumerRecord<String, String> record : records) { // 想把数据保存到数据库,成功就成功,不成功... // TODO record 2 db System.out.printf("patition = %d , offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value()); // 如果失败,则回滚, 不要提交offset } // 如果成功,手动通知offset提交 consumer.commitAsync(); } } /* 手动提交offset,并且手动控制partition */ private static void commitedOffsetWithPartition() { Properties props = new Properties(); props.setProperty("bootstrap.servers", "192.168.220.128:9092"); props.setProperty("group.id", "test"); props.setProperty("enable.auto.commit", "false"); props.setProperty("auto.commit.interval.ms", "1000"); props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer(props); // 消费订阅哪一个Topic或者几个Topic consumer.subscribe(Arrays.asList(TOPIC_NAME)); while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(10000)); // 每个partition单独处理 for(TopicPartition partition : records.partitions()){ List<ConsumerRecord<String, String>> pRecord = records.records(partition); for (ConsumerRecord<String, String> record : pRecord) { System.out.printf("patition = %d , offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value()); } long lastOffset = pRecord.get(pRecord.size() -1).offset(); // 单个partition中的offset,并且进行提交 Map<TopicPartition, OffsetAndMetadata> offset = new HashMap<>(); offset.put(partition,new OffsetAndMetadata(lastOffset+1)); // 提交offset consumer.commitSync(offset); System.out.println("=============partition - "+ partition +" end================"); } } } /* 手动提交offset,并且手动控制partition,更高级 */ private static void commitedOffsetWithPartition2() { Properties props = new Properties(); props.setProperty("bootstrap.servers", "192.168.220.128:9092"); props.setProperty("group.id", "test"); props.setProperty("enable.auto.commit", "false"); props.setProperty("auto.commit.interval.ms", "1000"); props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer(props); // jiangzh-topic - 0,1两个partition TopicPartition p0 = new TopicPartition(TOPIC_NAME, 0); TopicPartition p1 = new TopicPartition(TOPIC_NAME, 1); // 消费订阅哪一个Topic或者几个Topic // consumer.subscribe(Arrays.asList(TOPIC_NAME)); // 消费订阅某个Topic的某个分区 consumer.assign(Arrays.asList(p0)); while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(10000)); // 每个partition单独处理 for(TopicPartition partition : records.partitions()){ List<ConsumerRecord<String, String>> pRecord = records.records(partition); for (ConsumerRecord<String, String> record : pRecord) { System.out.printf("patition = %d , offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value()); } long lastOffset = pRecord.get(pRecord.size() -1).offset(); // 单个partition中的offset,并且进行提交 Map<TopicPartition, OffsetAndMetadata> offset = new HashMap<>(); offset.put(partition,new OffsetAndMetadata(lastOffset+1)); // 提交offset consumer.commitSync(offset); System.out.println("=============partition - "+ partition +" end================"); } } } /* 手动指定offset的起始位置,及手动提交offset */ private static void controlOffset() { Properties props = new Properties(); props.setProperty("bootstrap.servers", "192.168.220.128:9092"); props.setProperty("group.id", "test"); props.setProperty("enable.auto.commit", "false"); props.setProperty("auto.commit.interval.ms", "1000"); props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer(props); // jiangzh-topic - 0,1两个partition TopicPartition p0 = new TopicPartition(TOPIC_NAME, 0); // 消费订阅某个Topic的某个分区 consumer.assign(Arrays.asList(p0)); while (true) { // 手动指定offset起始位置 /* 1、人为控制offset起始位置 2、如果出现程序错误,重复消费一次 */ /* 1、第一次从0消费【一般情况】 2、比如一次消费了100条, offset置为101并且存入Redis 3、每次poll之前,从redis中获取最新的offset位置 4、每次从这个位置开始消费 */ consumer.seek(p0, 700); ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(10000)); // 每个partition单独处理 for(TopicPartition partition : records.partitions()){ List<ConsumerRecord<String, String>> pRecord = records.records(partition); for (ConsumerRecord<String, String> record : pRecord) { System.err.printf("patition = %d , offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value()); } long lastOffset = pRecord.get(pRecord.size() -1).offset(); // 单个partition中的offset,并且进行提交 Map<TopicPartition, OffsetAndMetadata> offset = new HashMap<>(); offset.put(partition,new OffsetAndMetadata(lastOffset+1)); // 提交offset consumer.commitSync(offset); System.out.println("=============partition - "+ partition +" end================"); } } } /* 流量控制 - 限流 */ private static void controlPause() { Properties props = new Properties(); props.setProperty("bootstrap.servers", "192.168.220.128:9092"); props.setProperty("group.id", "test"); props.setProperty("enable.auto.commit", "false"); props.setProperty("auto.commit.interval.ms", "1000"); props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); KafkaConsumer<String, String> consumer = new KafkaConsumer(props); // jiangzh-topic - 0,1两个partition TopicPartition p0 = new TopicPartition(TOPIC_NAME, 0); TopicPartition p1 = new TopicPartition(TOPIC_NAME, 1); // 消费订阅某个Topic的某个分区 consumer.assign(Arrays.asList(p0,p1)); long totalNum = 40; while (true) { ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(10000)); // 每个partition单独处理 for(TopicPartition partition : records.partitions()){ List<ConsumerRecord<String, String>> pRecord = records.records(partition); long num = 0; for (ConsumerRecord<String, String> record : pRecord) { System.out.printf("patition = %d , offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value()); /* 1、接收到record信息以后,去令牌桶中拿取令牌 2、如果获取到令牌,则继续业务处理 3、如果获取不到令牌, 则pause等待令牌 4、当令牌桶中的令牌足够, 则将consumer置为resume状态 */ num++; if(record.partition() == 0){ if(num >= totalNum){ consumer.pause(Arrays.asList(p0)); } } if(record.partition() == 1){ if(num == 40){ consumer.resume(Arrays.asList(p0)); } } } long lastOffset = pRecord.get(pRecord.size() -1).offset(); // 单个partition中的offset,并且进行提交 Map<TopicPartition, OffsetAndMetadata> offset = new HashMap<>(); offset.put(partition,new OffsetAndMetadata(lastOffset+1)); // 提交offset consumer.commitSync(offset); System.out.println("=============partition - "+ partition +" end================"); } } } }