新的生产者是线程安全的,在线程之间共享单个生产者实例,通常单例比多个实例要快。
Kafka消费者不是线程安全的
所以下面主要是消费者的大体,也没有实际的例子,提供思路
来自多线程处理在页面最后一部分
所有网络I/O都发生在进行调用应用程序的线程中。
用户的责任是确保多线程访问正确同步的。非同步访问将导致ConcurrentModificationException。
此规则唯一的例外是wakeup()
,它可以安全地从外部线程来中断活动操作。在这种情况下,将从操作的线程阻塞并抛出一个WakeupException。这可用于从其他线程来关闭消费者。 以下代码段显示了典型模式:
public class KafkaConsumerRunner implements Runnable {
private final AtomicBoolean closed = new AtomicBoolean(false);
private final KafkaConsumer consumer;
public void run() {
try {
consumer.subscribe(Arrays.asList("topic"));
while (!closed.get()) {
ConsumerRecords records = consumer.poll(Duration.ofMillis(100));
//消费消息的操作
}
} catch (WakeupException e) {
//关闭时忽略异常
if (!closed.get()) throw e;//但是没成功关闭就会报异常
} finally {
consumer.close();
}
}
// 可以从单独的线程关闭的方法
public void shutdown() {
closed.set(true);
consumer.wakeup();
}
}
在单独的线程中,可以通过设置关闭标志和唤醒消费者来关闭消费者。
上面的也是用下面这俩个来关闭消费者
closed.set(true);
consumer.wakeup();
1、每个线程一个消费者的优点
- 这是最容易实现的
- 因为它不需要在线程之间协调,所以通常它是最快的。
- 它按顺序处理每个分区(每个线程只处理它接受的消息)
2、每个线程一个消费者的缺点
- 更多的消费者意味着更多的TCP连接到集群(每个线程一个)。一般kafka处理连接非常的快,所以这是一个小成本。
- 更多的消费者意味着更多的请求被发送到服务器,但稍微较少的数据批次可能导致I/O吞吐量的一些下降。
- 所有进程中的线程总数受到分区总数的限制。
另一个替代方式是一个或多个消费者线程,它来消费所有数据,其消费所有数据并将ConsumerRecords实例切换到由实际处理记录处理的处理器线程池来消费的阻塞队列,但也有优缺点,下面列出来了
3、解耦消费和处理优点
- 可扩展消费者和处理进程的数量。这样单个消费者的数据可分给多个处理器线程来执行,避免对分区的任何限制。
4、解耦消费和处理缺点
- 跨多个处理器的顺序保证需要特别注意,因为线程是独立的执行,后来的消息可能比遭到的消息先处理,这仅仅是因为线程执行的运气。如果对排序没有问题,这就不是个问题。
- 手动提交变得更困难,因为它需要协调所有的线程以确保处理对该分区的处理完成。