分享一些 Kafka 消费数据的小经验

标签: Kafka Java 进阶 Kafka | 发表时间:2018-11-20 00:02 | 作者:
出处:http://crossoverjie.top/

前言

之前写过一篇 《从源码分析如何优雅的使用 Kafka 生产者》 ,有生产者自然也就有消费者。

建议对 Kakfa 还比较陌生的朋友可以先看看。

就我的使用经验来说,大部分情况都是处于数据下游的消费者角色。也用 Kafka 消费过日均过亿的消息(不得不佩服 Kakfa 的设计),本文将借助我使用 Kakfa 消费数据的经验来聊聊如何高效的消费数据。

单线程消费

以之前生产者中的代码为例,事先准备好了一个 Topic:data-push,3个分区。

先往里边发送 100 条消息,没有自定义路由策略,所以消息会均匀的发往三个分区。

先来谈谈最简单的单线程消费,如下图所示:

由于数据散列在三个不同分区,所以单个线程需要遍历三个分区将数据拉取下来。

单线程消费的示例代码:

这段代码大家在官网也可以找到:将数据取出放到一个内存缓冲中最后写入数据库的过程。

先不讨论其中的 offset 的提交方式。

通过消费日志可以看出:

取出的 100 条数据确实是分别遍历了三个分区。

单线程消费虽然简单,但存在以下几个问题:

  • 效率低下。如果分区数几十上百个,单线程无法高效的取出数据。
  • 可用性很低。一旦消费线程阻塞,甚至是进程挂掉,那么整个消费程序都将出现问题。

多线程消费

既然单线程有诸多问题,那是否可以用多线程来提高效率呢?

在多线程之前不得不将消费模式分为两种进行探讨:消费组、独立消费者。

这两种消费模式对应的处理方式有着很大的不同,所以很有必要单独来讲。

独立消费者模式

先从 独立消费者模式谈起,这种模式相对于消费组来说用的相对小众一些。

看一个简单示例即可知道它的用法:

值得注意的是:独立消费者可以不设置 group.id 属性。

也是发送100条消息,消费结果如下:

通过 API 可以看出:我们可以手动指定需要消费哪些分区。

比如 data-push Topic 有三个分区,我可以手动只消费其中的 1 2 分区,第三个可以视情况来消费。

同时它也支持多线程的方式,每个线程消费指定分区进行消费。

为了直观,只发送了 10 条数据。

根据消费结果可以看出:

c1 线程只取 0 分区;c2 只取 1 分区;c3 只取 2 分区的数据。

甚至我们可以将消费者多进程部署,这样的消费方式如下:

假设 Topic:data-push 的分区数为 4 个,那我们就可以按照图中的方式创建两个进程。

每个进程内有两个线程,每个线程再去消费对应的分区。

这样当我们性能不够新增 Topic 的分区数时,消费者这边只需要这样水平扩展即可,非常的灵活。

这种自定义分区消费的方式在某些场景下还是适用的,比如生产者每次都将某一类的数据只发往一个分区。这样我们就可以只针对这一个分区消费。

但这种方式有一个问题:可用性不高,当其中一个进程挂掉之后;该进程负责的分区数据没法转移给其他进程处理。

消费组模式

消费组模式应当是使用最多的一种消费方式。

我们可以创建 N 个消费者实例( new KafkaConsumer()),当这些实例都用同一个 group.id 来创建时,他们就属于同一个消费组。

在同一个消费组中的消费实例可以收到消息,但一个分区的消息只会发往一个消费实例。

还是借助官方的示例图来更好的理解它。

某个 Topic 有四个分区 p0 p1 p2 p3,同时创建了两个消费组 groupA,groupB

  • A 消费组中有两个消费实例 C1、C2
  • B 消费组中有四个消费实例 C3、C4、C5、C6

这样消息是如何划分到每个消费实例的呢?

通过图中可以得知:

  • A 组中的 C1 消费了 P0 和 P3 分区;C2 消费 P1、P2 分区。
  • B 组有四个实例,所以每个实例消费一个分区;也就是消费实例和分区是一一对应的。

需要注意的是:

这里的消费实例简单的可以理解为 new KafkaConsumer它和进程没有关系


比如说某个 Topic 有三个分区,但是我启动了两个进程来消费它。

其中每个进程有两个消费实例,那其实就相当于有四个实例了。

这时可能就会问 4 个实例怎么消费 3 个分区呢?

消费组自平衡

这个 Kafka 已经帮我做好了,它会来做消费组里的 Rebalance

比如上面的情况,3 个分区却有 4 个消费实例;最终肯定只有三个实例能取到消息。但至于是哪三个呢,这点 Kakfa 会自动帮我们分配好。

看个例子,还在之前的 data-push 这个 Topic,其中有三个分区。

当其中一个进程(其中有三个线程,每个线程对应一个消费实例)时,消费结果如下:

里边的 20 条数据都被这个进程的三个实例消费掉。

这时我新启动了一个进程,程序和上面那个一模一样;这样就相当于有两个进程,同时就是 6 个实例。

我再发送 10 条消息会发现:

进程1 只取到了分区 1 里的两条数据(之前是所有数据都是进程1里的线程获取的)。


同时进程2则消费了剩下的 8 条消息,分别是分区 0、2 的数据(总的还是只有三个实例取到了数据,只是分别在不同的进程里)。


当我关掉进程2,再发送10条数据时会发现所有数据又被进程1里的三个线程消费了。

通过这些测试相信大家已经可以看到消费组的优势了。

我们可以在一个消费组中创建多个消费实例来达到高可用、高容错的特性,不会出现单线程以及独立消费者挂掉之后数据不能消费的情况。同时基于多线程的方式也极大的提高了消费效率。

而当新增消费实例或者是消费实例挂掉时 Kakfa 会为我们重新分配消费实例与分区的关系就被称为消费组 Rebalance

发生这个的前提条件一般有以下几个:

  • 消费组中新增消费实例。
  • 消费组中消费实例 down 掉。
  • 订阅的 Topic 分区数发生变化。
  • 如果是正则订阅 Topic 时,匹配的 Topic 数发生变化也会导致 Rebalance

所以推荐使用这样的方式消费数据,同时扩展性也非常好。当性能不足新增分区时只需要启动新的消费实例加入到消费组中即可。

总结

本次只分享了几个不同消费数据的方式,并没有着重研究消费参数、源码;这些内容感兴趣的话可以在下次分享。

文中提到的部分源码可以在这里查阅:

https://github.com/crossoverJie/JCSprout

欢迎关注公众号一起交流:

相关 [分享 kafka 消费] 推荐:

分享一些 Kafka 消费数据的小经验

- - crossoverJie's Blog
之前写过一篇 《从源码分析如何优雅的使用 Kafka 生产者》 ,有生产者自然也就有消费者. 建议对 Kakfa 还比较陌生的朋友可以先看看. 就我的使用经验来说,大部分情况都是处于数据下游的消费者角色. 也用 Kafka 消费过日均过亿的消息(不得不佩服 Kakfa 的设计),本文将借助我使用 Kakfa 消费数据的经验来聊聊如何高效的消费数据.

Kafka重复消费和丢失数据研究 | Zollty's Blog

- -
底层根本原因:已经消费了数据,但是offset没提交. 原因1:强行kill线程,导致消费后的数据,offset没有提交. 原因2:设置offset为自动提交,关闭kafka时,如果在close之前,调用 consumer.unsubscribe() 则有可能部分offset没提交,下次重启会重复消费.

kafka消费者客户端 - sowhat1943 - 博客园

- -
消费者与消费者组之间的关系. 每一个消费者都隶属于某一个消费者组,一个消费者组可以包含一个或多个消费者,每一条消息只会被消费者组中的某一个消费者所消费. 不同消费者组之间消息的消费是互不干扰的. 消费者组出现主要是出于两个目的:. (1) 使整体的消费能力具备横向的伸缩性. 可以适当增加消费者组中消费者的数量,来提高整体的消费能力.

kafka监控之kafka-run-class.sh

- - 开源软件 - ITeye博客
kafka自带了很多工具类,在源码kafka.tools里可以看到:. 这些类该如何使用呢,kafka的设计者早就为我们考虑到了,在${KAFKA_HOME}/bin下,有很多的脚本,其中有一个kafka-run-class.sh,通过这个脚本,可以调用其中的tools的部分功能,如调用kafka.tools里的ConsumerOffsetChecker.scala,.

闲扯kafka mq

- - 开源软件 - ITeye博客
本文主要讲解关于kafka mq的设计思想及个人理解. 关于kafka的详细信息,大家可以参考官网的文献 http://kafka.apache.org/documentation.html这是一篇相当不错的文章,值得仔细研读. 第一个问题:消息队列(Message Queue)是干嘛用的. 首先,要对消息队列有一个基本的理解.

Kafka优化

- - ITeye博客
配置优化都是修改server.properties文件中参数值. 1.网络和io操作线程配置优化. # broker处理消息的最大线程数. # broker处理磁盘IO的线程数. 一般num.network.threads主要处理网络io,读写缓冲区数据,基本没有io等待,配置线程数量为cpu核数加1.

Kafka Connect简介

- - 鸟窝
Kafka 0.9+增加了一个新的特性 Kafka Connect,可以更方便的创建和管理数据流管道. 它为Kafka和其它系统创建规模可扩展的、可信赖的流数据提供了一个简单的模型,通过 connectors可以将大数据从其它系统导入到Kafka中,也可以从Kafka中导出到其它系统. Kafka Connect可以将完整的数据库注入到Kafka的Topic中,或者将服务器的系统监控指标注入到Kafka,然后像正常的Kafka流处理机制一样进行数据流处理.

kafka consumer group offset

- - 开源软件 - ITeye博客
     kafka0.9及以前版本kafka offset 保存在zookeeper, 因频繁读写zookeeper性能不高;从0.10开始,主题分区offset存储于kafka独立主题中.     管理监控kafka主题及分区offset至关重要,原网上很开源流行工具KafkaOffsetMonitor、kafka-manager,旧版offset保存于zookeeper,kafka consumer无相应API,从kafka0.10.1.1以后提供相应API读取主题分区offset(也可以调用KafkaClient API,kafka管理API由scala语言编写).

Swipe:另类的消费分享服务

- cgeek - WebLeOn's Blog
用户如果愿意分享消费记录或者Wishlist,对于商家或者广告主来说会有很大的价值. 但从用户的角度来讲,却往往没有兴趣主动分享这些信息. Swipe也是一个分享消费记录和愿望列表的服务,但是它却包含了不少最流行的互联网应用元素. 用Facebook就可以直接登录Swipe,并可以方便地把在Swipe发布的内容直接发送到涂鸦墙,分享给Facebook好友.

Kafka设计解析(二):Kafka High Availability (上)

- -
Kafka在0.8以前的版本中,并不提供High Availablity机制,一旦一个或多个Broker宕机,则宕机期间其上所有Partition都无法继续提供服务. 若该Broker永远不能再恢复,亦或磁盘故障,则其上数据将丢失. 而Kafka的设计目标之一即是提供数据持久化,同时对于分布式系统来说,尤其当集群规模上升到一定程度后,一台或者多台机器宕机的可能性大大提高,对Failover要求非常高.