kafka 基础知识
1.消费者api
1.消费者概念
1)每个消费者属于一个消费者组。topic 的一个分区只会给一个消费者组下的一个消费者
2)如果要实现一个广播的效果,那只需要不同的group_id去消费。
3)如果consumer.group中某个消费者挂了,会自动把分配给他的分区分配其他的消费者。等它重启后再归还给它。
2.consumer实现代码
public class Consumer {
private static final String SERVERS="dev0:9092,dev1:9092,dev2:9092";
public static void main(String[] args) throws InterruptedException {
//atomic 原子
AtomicBoolean isRunning=new AtomicBoolean(true);
//参数配置
Properties pros = new Properties();
pros.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
pros.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class.getName());
pros.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,SERVERS);
//自动设置读取的起始的offset,值可以是earliest,lastet,none
pros.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
//是否自动提交offset
pros.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,true);
//设置消费者的id
pros.put(ConsumerConfig.GROUP_ID_CONFIG,"g1");
//构建consumer
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(pros);
//订阅主题
consumer.subscribe(Arrays.asList("test"));
//拉取消息
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
while (isRunning.get()) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(Long.MAX_VALUE));
for(ConsumerRecord<String,String> record:records){
//do some process
System.out.println(record.key()+","
+record.value()+","
+record.topic()+","
+record.partition()+","
+record.offset());
System.out.println("------华丽的分割线------");
}
}
}
});
thread.start();
Thread.sleep(60000);
isRunning.set(false);
//关闭连接
consumer.close();
}
}
3.订阅方式
3.1 集合方式订阅主题
consumer.subscribe(Arrays.asList("test"));
3.2 正则方式订阅主题
consumer.subscribe(Pattern.compile("topic*"))
3.3 assign 订阅主题
消费者不仅可以通过kafkaConsumer.subscribe()订阅主题,还可直接订阅某些主题的指定分区
consumer.assign(Arrays.asList(new TopicPartition("topic",0),new TopicPartition("topic_1",1)));
3.4 subscribe和assign区别
1.通过subscribe()方法订阅主题具有消费者自动再均衡
2.assgin()订阅分区,是不具备自动再平衡的,因为subsribe有consumerRebalanceListener
3.5 取消订阅
consumer.unsubscribe();
3.6消息的消费模式
kafka中消费是基于拉模式。kafka的重复调用poll方法返回数据。
consumerRecords<k,v>poll(final Duration timeout)
timeout设置为long.MAX_VALUE;
3.7 指定位移消费
public class Consumer2 {
private static final String SERVERS="dev0:9092,dev1:9092,dev2:9092";
public static void main(String[] args) throws InterruptedException {
//atomic 原子
AtomicBoolean isRunning=new AtomicBoolean(true);
//参数配置
Properties pros = new Properties();
pros.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
pros.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,StringDeserializer.class.getName());
pros.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,SERVERS);
//自动设置读取的起始的offset,值可以是earliest,lastet,none
pros.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
//是否自动提交offset
pros.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,true);
//设置消费者的id
pros.put(ConsumerConfig.GROUP_ID_CONFIG,"g1");
//构建consumer
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(pros);
//订阅主题
consumer.subscribe(Arrays.asList("test"));
//调用一次poll
consumer.poll(Duration.ofMillis(10000));
//获取所分配的分区信息,那些topic的哪些分区
Set<TopicPartition> assignment = consumer.assignment();
for(TopicPartition topicPartition:assignment){
//为指定partition设置读取起始分区offset
consumer.seek(topicPartition,2106L);
}
//拉取消息
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
while (isRunning.get()) {
//拉取数内容
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(Long.MAX_VALUE));
for(ConsumerRecord<String,String> record:records){
//do some process
System.out.println(record.key()+","
+record.value()+","
+record.topic()+","
+record.partition()+","
+record.offset());
System.out.println("------华丽的分割线------");
}
}
}
});
thread.start();
Thread.sleep(60000);
isRunning.set(false);
//关闭连接
consumer.close();
}
}
3.8 consumer重点核心参数解析
【auto.offset.reset】
earliest
当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
topica -> partition0:1000
partitino1:2000
latest
当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从当前位置开始消费
none
topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
注:我们生产里面一般设置的是latest
【enable.auto.commit】
这个就是开启自动提交唯一,定期提交。默认情况下消费每隔5秒将拉取最大的消费偏移量进行提交。自动位移提交动作是poll方法逻辑完成的。
可能是重复消息和消息丢失问题。
可以使用手动提交。
【auto.commit.ineterval.ms】
这个指的是多久条件一次偏移量
3.9 日志分段切分条件
1.日志分段1个Gb log
2.偏移量
3.10 性能测试和异常感知
–messages 1000000 --broker-list dev0:9092 --consumer-props consumer.auto.offset.resert=earliest
异常感知
heart.interval.ms:
consumer心跳时间间隔。coordinator保持心跳才能知道consumer是否故障。
pros.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG,3000)
session.timeout.ms
10秒
pros.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG,10*1000)
max.poll.interval.ms
两次拉取poll操作超过这个时间。就是太弱了。
pros.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG,10*1000)