阿里架构师:对于 Kafka 的消费者客户端详解,你都明白吗?

前言

前面讲解了 Kafka 的生产者,而与生产对应的就是消费者,程序中可以通过 KafkaConsumer 来订阅主题,并从订阅的主题中拉取消息。而 Kafka 中消费者比生产者多了个组的概念,也称消费者组,从而提升单机的消费速度。本文将介绍下消费者与消费者组的概念,然后再对客户端开发进行详细讲解。

一、消费者与消费者组

消费者负责订阅 Kafka 中的主题,并且从上面拉取消息,但与生产者不同的是它增加了消费者组的概念,这是因为很多时候 Kafka 的消费者在消费消息的时候经常会做一些高延时的动作,比如把数据写到数据库,读取数据进行计算处理等,这就相对于 producer 慢的多了,因此消费者组的增加是用来提升 Kafka 的消费能力而出现的,当同一个主题的消息再次过来的时候,这些消息就会被同一个消费者组的消费者来共同消费。

1.1 图解消费者模型

下面,我们来看看这个消费的过程。

情形一:

比如公司里有个打印服务,假设有 6 个打印分区,分别对应 彩印word、彩印excel、彩印ppt、黑白word、黑白excel、黑白ppt 六个分区内容,此时只要一台打印机。如下

情形二:

但是这个打印机打印的效果实在太慢了,很多人一天到晚都挤在打印室排队打印文档。这时,公司就新购了台打印机,让它们分别处理打印请求,可以把它们放在一个消费者组中,同时消费这些分区的数据。

此时它们就分别处理所分配到分区的数据,逻辑上彼此不干扰。同一个主题中的消息只会发布给消费者组中的一个消费者

情形三:

此时,公司想要加个打印备份功能,于是又采购了一个打印机,用来同步打印所有的打印文件。(ps :我也不知道这是什么奇葩公司,为了场景随便举的例子~)

如下:

这时候每个分区的数据都会发送到消费者组B 中即同一个分区的消息可以被不同消费者组的消费者消费

情形四:

此时,公司为了准备融资,给投资人秀秀自己的肌肉,于是又请购了五台打印机,这时候的场景如下:

虽然说消费者与消费者组这种模型可以让整体的消费能力具备横向伸缩性,但是对于分区固定的情况下,增加消费者并不一定能提升消费能力,如图所示,此时就有一台打印机无法分配到分区而消费不了数据。

1.2 消息投递模式

之前说过消息队列的两种模式,即点对点和发布订阅模式。而 Kafka 同时支持这两种模式。下面的这个理解很关键。

  • 点对点模式基于队列,类似于同一个消费者组中的数据,由生产者发送数据到分区,然后消费者拉取分区的消息进行消费,此时消息只能被同一个消费者组的消费者消费一次。
  • 发布订阅模式模式就是 kafka 中的分区消息可以被不同消费者组的消费者消费。这就是一对多的广播模式应用。

当然,消费者组是一个逻辑的概念,通过客户端参数 group.id 来配置,默认值为空字符串。而消费者并不是逻辑的概念,它是真正消费数据的实体,可以是线程、也可以是一个机器。

好,明白了消费者与消费者组的概念,接下来我们正式打开 消费者客户端的潘多拉魔盒。

二、Kafka 消费者的应用

同样,消费者也是依赖于 Kafak 的客户端,正常的消费逻辑是下面几个步骤:

  • 1、配置消费者客户端参数及创建相应的消费者实例
  • 2、订阅主题
  • 3、拉取消息并消费
  • 4、提交消费位移
  • 5、关闭消费者实例

这里的位移可能我们还不清楚是什么意思,别急,我们后面会讲到,先来看下一个典型的消费者它应该怎么写。

2.1 消费者客户端演示

public class Consumer {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "192.168.81.101:9092");

        props.put("group.id", "test"); //消费者组
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
​
        consumer.subscribe(Arrays.asList("xiaolei2"));
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            for (ConsumerRecord<String, String> record : records){
                System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
            }
        }
    }
}

2.2 必要参数配置

在创建消费者的时候,Kafka 有 4 个参数 是必填的,比生产者多了一个。

  • bootstrap.servers : 这个参数用来指定连接 Kafka 集群的 broker 地址列表,可以是单个地址,也可以用逗号分割填上 Kafka 集群地址。
  • key.deserializer 和 value. deserializer :因为消息发送的时候将key 和 value 进行序列化生成字节数组,因此消费数据的时候需要反序列化为原来的数据。
  • group.id : 消费者所在组的名称,默认值为 ”“,如果设置为空,则会抛出异常 Exception in thread "main" org.apache.kafka.common.errors.InvalidGroupIdException: To use the group management or offset commit APIs, you must provide a valid group.id in the consumer configuration. 复制代码

2.3 订阅主题与分区

在创建出 consumer 之后,我们需要为它订阅相关的主题,一个消费者可以订阅一个或多个主题。这里可以使用两个 API

  • consumer.subscribe(Collection topics) :指明需要订阅的主题的集合;
  • consumer.subscribe(Pattern pattern) :使用正则来匹配需要订阅的集合。

对于它订阅的是个集合,我们也容易理解,Kafka 可以通过正则表达式 来匹配相关主题,例如下面的这样:

consumer.subscribe(Pattern.compile("topic-.*"));

但是如果 consumer 重复定义的话,就以后面的为准,下面订阅的就是 xiaolei3 这个主题。

consumer.subscribe(Arrays.asList("xiaolei2"));
consumer.subscribe(Arrays.asList("xiaolei3"));

订阅完主题,我们讲讲它怎么定义分区。

直接订阅特定分区。

 consumer.assign(Arrays.asList(new TopicPartition("xiaolei2",0)));

这里面使用了 assing 方法来订阅特定分区。那如果不知道有哪些分区怎么办呢?

可以使用 KafkaConsumer 的 partitionsFor() 方法用来查询指定主题的元数据信息。

下面这种实现:

        consumer.assign(Arrays.asList(new TopicPartition("xiaolei2",0)));
        ArrayList<TopicPartition> topicPartitions = new ArrayList<>();
        List<PartitionInfo> partitionInfos 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1/kafka是一个分布式的消息缓存系统 2/kafka集群中的服务器都叫做broker 3/kafka有两类客户端,一类叫producer(消息生产者),一类叫做consumer(消息消费者),客户端和broker服务器之间采用tcp协议连接 4/kafka中不同业务系统的消息可以通过topic进行区分,而且每一个消息topic都会被分区,以分担消息读写的负载 5/每一个分区都可以有多个副本,以防止数据的丢失 6/某一个分区中的数据如果需要更新,都必须通过该分区所有副本中的leader来更新 7/消费者可以分组,比如有两个消费者组A和B,共同消费一个topic:order_info,A和B所消费的消息不会重复 比如 order_info 中有100个消息,每个消息有一个id,编号从0-99,那么,如果A组消费0-49号,B组就消费50-99号 8/消费者在具体消费某个topic中的消息时,可以指定起始偏移量 每个partition只能同一个group中的同一个consumer消费,但多个Consumer Group可同时消费同一个partition。 n个topic可以被n个Consumer Group消费,每个Consumer Group有多个Consumer消费同一个topic Topic在逻辑上可以被认为是一个queue,每条消费都必须指定它的Topic,可以简单理为必须指明把这条消息放进哪个queue里。为了使得Kafka的吞吐率可以线性提高,物理上把Topic分成一个或多个Partition,每个Partition在物理上对应一个文件夹,该文件夹下存储这个Partition的所有消息和索引文件。若创建topic1和topic2两个topic,且分别有13个和19个分区 Kafka的设计理念之一就是同时提供离线处理和实时处理。根据这一特性,可以使用Storm这种实时流处理系统对消息进行实时在线处理,同时使用Hadoop这种批处理系统进行离线处理,还可以同时将数据实时备份到另一个数据中心,只需要保证这三个操作所使用的Consumer属于不同的Consumer Group即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值