Kafka使用过程中遇到的一些问题
最近工作中需要一个日志收集系统,使用了kafka来实现。日志收集系统主要功能是,producer将接收到的logs存储到kafka里,然后consumer从kafka里边取数据进行消费处理。由于没有接触过kafka,在使用中遇到了一些问题,在此做个记录。
问题 1. consumer有时候可以消费topic,有时候却不能消费
基本情况:
- 配置两个consumer group,这两个consumer group用于消费同一个topic,但做不同的处理任务。每个consumer group中都只有一个consumer实例进行消费。
- 一个topic,此topic只配置了一个partition。
问题:
两个consumer group都用来消费同一个topic,测试时发现,在有时候,consumer1(属于consumer group1)能消费,consumer2(属于consumer group2)却不能消费。Topic有一个partition,两个consumer group都只有一个consumer实例,每个consumer实例都应该能够被分配到这唯一的partition进行消费,为什么会出现有的consumer不能消费的情况?
原因:
查看程序log发现,在存在问题的时候,consumer1分配到了partition,consumer2却没有分配到partition,从而导致只有consumer1有消费,consumer2没有消费。为什么consumer2没有分配到partition,这实在令人费解!
原来,之前在服务器上测试时已经运行了此程序,在本地主机进行测试时又运行了一个,即服务器和本地主机同时运行了此日志收集程序,虽然在此程序中每个consumer group只有一个consumer实例,但是服务器上的程序和本地主机上的程序各创建了一个consumer实例,这两个consumer实例拥有相同的group ID,实质上导致了每个consumer group有两个consumer实例。Topic只有一个partition,每个consumer group有两个consumer实例,这两个consumer实例只能有一个被分配到partition并消费。
在kafka中,每个consumer实例都有一个group ID用于标识它是属于哪一个group,group ID相同的各个consumer实例都属于同一个consumer group。本地主机上运行的程序创建的consumer2(属于consumer group2)与服务器上运行的程序创建的consumer2拥有同一个group ID,因此属于同一个group,而此topic只有一个partition,因此这两个consumer只能有一个能够分配到这个partition进行消费。暂时关闭服务器上的程序后,一切就恢复了正常。
问题 2. 两台设备上只有一个上存在logs
基本情况:
- 一个topic,此topic配置了四个partition。
- 两个consumer group,这两个consumer group用于消费同一个topic,但做不同的处理任务。每个consumer group中都只有一个consumer实例进行消费。
- 两台服务器,都运行此日志收集程序。
问题:
两个consumer group用于消费同一个topic并做不同的处理,其中一个consumer group(称作 group2)是将消费到的日志写入服务器磁盘文件中。有两台服务器都在运行此日志收集程序,每个服务器上的程序都创建了一个group2的consumer实例,此consumer实例会分配到两个partition进行处理,因此每个服务器都只存储了一部分日志文件。但是在测试时发现,所有日志都写入了server1,server2上没有日志,即便使用测试工具发送了大量数据,server2仍然没有日志。
原因:
查看log发现,server1上的consumer实例分配的partition为partition_0 partition_1,server2上的consumer实例分配的partition为partition_3、partition_4,两个server上的consumer实例都被分配了partition,partition分配正常,消费应该没有问题。server2上没有日志数据,说明没有数据供其消费,也就是说,所有数据都被producer发送到了partition_1或partition_2上,这是生产的问题,应该是与生产者的分区路由有关,因此有必要了解下生产者的分区路由策略。
Kafka中的每个Topic分配了4个Partition,生产者(Producer)在将消息记录(ProducerRecord)发送到某个Topic时是要选择对应的Partition的,选择Partition的策略如下:
- 判断消息中的partition字段是否有值,有值的话就是指定了partition,直接将该消息发送到指定的partition就行。
- 如果没有指定分区(partition),则使用分区器进行分区路由,首先判断消息中是否指定了key。
- 如果指定了key,则使用该key进行hash操作,并转为正数,然后将其对topic相应的分区数进行取余操作,得到一个分区。
- 如果没有指定key,则在一个随机数上以自增的方式产生一个数(第一次时生成随机数,之后在其基础上进行自增),转为正数之后对分区数量进行取余操作,得到一个分区。
由于在程序中Producer发送记录的时候指定了固定的key,根据这个key进行分区路由总是会选择同一个分区,所有日志都被发送给了同一个分区,因此只有关联这个分区的consumer实例才能消费,只有此consumer实例所在的server上才有日志。
参考链接:
https://blog.csdn.net/abinge317/article/details/84542073