唯's Blog

笔者是一个热爱编程的 Java 程序员。

0%

Kafka线上问题

消费客户端(Consumer)频繁出现Rebalance

心跳超时会引发Rebalance,可以通过参数调整、提高消费速度等方法解决。

.最多一次(At-most-once)

最多一次其实非常容易保证的,UDP 这种传输层的协议其实保证的就是最多一次消息投递,消息的发送者只会尝试发送该消息一次,并不会关心该消息是否得到了远程节点的响应。

无论该请求是否发送给了接受者,发送者都不会重新发送这条消息;这其实就是最最基本的消息投递语义,然而消息可能由于网络或者节点的故障出现丢失。

这本质上是一种尽力而为的方法。

至少一次(At-least-once)

为了解决最多一次时的消息丢失问题,消息的发送者需要在网络出现超时重新发送相同的消息,也就是引入超时重试的机制,在发送者发出消息会监听消息的响应,如果超过了一定时间也没有得到响应就会重新发送该消息,直到得到确定的响应结果。

对于最少一次的投递语义,我们不仅需要引入超时重试机制,还需要关心每一次请求的响应,只有这样才能确保消息不会丢失,但是却可能会造成消息的重复,这就是最少一次在解决消息丢失后引入的新问题。

精确一次(Exactly-once)

虽然最少一次解决了最多一次的消息丢失问题,但是由于重试却带来了另一个问题 - 消息重复,也就是接受者可能会多次收到同一条消息;从理论上来说,在分布式系统中想要解决消息重复的问题是不可能的,很多消息服务提供了正好一次的 QoS 其实是在接收端进行了去重。

消息去重需要生产者生产消息时加入去重的 key,消费者可以通过唯一的 key 来判断当前消息是否是重复消息,从消息发送者的角度来看,实现正好一次的投递是不可能的,但是从整体来看,我们可以通过唯一 key 或者重入幂等的方式对消息进行『去重』。

消息的重复是不可能避免的,除非我们允许消息的丢失,然而相比于丢失消息,重复发送消息其实是一种更能让人接受的处理方式,因为一旦消息丢失就无法找回,但是消息重复却可以通过其他方法来避免副作用。

提高消费速度

提高消费速度有以下两个办法:

  • 增加Consumer实例个数。

    可以在进程内直接增加(需要保证每个实例对应一个线程,否则没有太大意义),也可以部署多个消费实例进程;需要注意的是,实例个数超过分区数量后就不再能提高速度,将会有消费实例不工作。

  • 增加消费线程。

    增加Consumer实例本质上也是增加线程的方式来提升速度,因此更加重要的性能提升方式是增加消费线程,最基本的步骤如下:

    1. 定义一个线程池。

    2. Poll数据。

    3. 把数据提交到线程池进行并发处理。

    4. 等并发结果返回成功后,再次poll数据执行。

消息过滤

消息队列Kafka版自身没有消息过滤的语义。实践中可以采取以下两个办法:

  • 如果过滤的种类不多,可以采取多个Topic的方式达到过滤的目的。

  • 如果过滤的种类多,则最好在客户端业务层面自行过滤。

实践中请根据业务具体情况进行选择,也可以综合运用上面两种办法。

提升发送性能

  • 建议您设置batch.size=16384linger.ms=1000