首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

每秒处理10万条消息的高性能MQ,Kafka是怎么做到的?

MQ(消息中间件)是项目开发中经常用到的一种技术。它是分布式系统重要的组件,主要用来解决应用解耦、异步任务、流量削锋等业务场景。MQ有非常多的开源实现,包括RocketMq、RabitMq、ActiveMq、Kafka等。在这些开源实现的组件中,Kafka是最流行的消息中间件,它以高吞吐、低延迟、可扩展、数据持久化等特点而受到开发人员的喜欢。每秒可处理10万条消息,这个级别可以满足大多数业务场景的需求。那Kafka是如何做到如此大的吞吐?Java语言中我们该如何使用Kafka呢?本文就将详细讲解这些知识。

01

Kafka 是什么?

LinkedIn(中文名为领英)是一家类似于FaceBook的社群网络,其用户群体大多是企业白领商业人士。通过在LinkedIn上注册账户,商业人士可以获取自己一个电子名片,维护他们在商业交往中认识并信任的联系人,这些人被称为“人脉”(Connections)。在LinkedIn网站上,每天活跃着大量的用户,这些用户每天都会产生海量的活动流数据,例如:访问页面操作、查看历史以及搜索内容等。同时,LinkedIn网站背后有一个庞大的计算机集群支持,公司运维人员需要监控每台机器的性能数据,包括CPU使用率、内存使用率、机器负载、服务器日志等。通常,用户活动流数据和服务器运维数据都是以文件的形式写入到日志,然后周期性的对这些文件进行分析得到最终的报表数据,这是一项复杂极其复杂且庞大的计算任务。为了提供更好的解决方案,LinkedIn的首席架构师Jay Kreps组件团队开发了分布式发布订阅消息系统Kafka。

Kafka一种高性能分布式基于发布/订阅的消息系统,采用Java和Scala语言开发。高吞吐和低延迟是它的两个核心特性,也是MQ消息中间件需要解决的核心问题。Kafka的主要特性表现在以下几个方面:

高吞吐:每秒可以处理几十万条消息,即使在非常廉价的商用机器上也能做到单机支持每秒10万条以上消息的传输。

低延迟:Kafka的最低延迟只有几毫秒。

持久化:提供消息持久化的能力,时间复杂为O(1),对TB级别的数据也能提供常数级别的复杂度的访问能力。

高伸缩:Kafka的消息按照topic(主题)进行分类,每个topic下有多个partition(分区),topic中的partition可以分布在不同的主机上,防止消息丢失。

容错性:Kafka集群中的一个节点宕机失败以后,集群仍然可以正常工作。

高并发:同时支持数千个客户端读写。

02

Kafka 是什么?

Kafka的高性能得益于它的几大组件的设计。Kafka主要包括以下几大组件:

Message:Kafka中的一条记录或数据单位。每条消息都有一个键和对应的一个值,有时还会有可选的消息头。

Broker:Kafka集群中的每台主机称为broker,Broker存储每条消息数据。

Topic:消息主题。Kafka中的每个消息都属于一个主题,每个主题保存在一个或多个Broker上。

Partition:Topic分区。每个Ttopic可以建立多个分区,分区的数量决定了客户端消费的能力。分区越多,客户端并发消费的能力越大。

Producer:消息的生产者,负责将消息发布到Broker。

Consumer:消费消费者,从Kafka Broker拉取消息。

Consumer Group:消费者组。每个Consumer都属于一个特定的Consumer Group。一条消息只能被同一个Consumer Group的一个Consumer消费,但是可以被不同Consumer Group的多个Consumer消费。

03

Kafka 架构设计

上图是Kafka的网络拓扑图。从图中可以看到,一个Kafka集群是由多个Kafka Broker组成的,集群的数量决定了整个集群的性能。项目实践中我们根据实际需求来决定集群规模,集群规模越大,吞吐率越大,当然Kafka支持水平扩展,可以根据实际需求来扩展集群数量。Producer是消费的生产方,Producer的应用类型比较多,如日志、前面提到的用户行为数据、服务器性能监控数据,这些数据通过Kafka Producer Api Push到Kafka的Broker。消息按照topic和partition存储在特定的broker上。

每个topic被分成多个partition,每个partition是以append log文件形式存储。Producer发送消息会被追加到log文件的尾部,每条消息在文件中的位置称为 offset(偏移量),offset 为一个 long 型的数字,它唯一标记一条消息。Append log是一种顺序写磁盘的机制,效率远高于随机写内存,这也是Kafka高吞吐的一个重要原因。

Consumer负责消费Broker中指定的Topic中的数据,因为Topic中的数据按照Partition分布式存储,所以程序可以根据Partition的数量来启动相应数量的Consumer个数来消费数据。如下图所示:

xiaomi_dispatch这个topic有15个partition,客户端就可以启动15个消费者(消费线程)来并行消费该topic下的消息,极大的提高消费速率。所以如果碰到消费者能力不足而导致kafka消息积压的时候,增加partition数量可以有效解决积压问题。

Consumer Group是consumer的集合,Consumer Group在Kafka中有着重要的作用。某个topic中的消息只能被Consumer Group中的一个Consumer消费,这样可以防止同一个Consumer Group中的多个Consumer重复消费消息。如果程序想要在多个地方消费某个topic中的消息,只要将Consumer放在不同的 Consumer Group即可。

Zookeeper是Kafka集群的注册中心,负责管理Kafka集群配置,包括broker 注册、topic 注册、producer、consumer 注册、维护 partition 与 consumer 的关系、记录消息消费的进度、producer 和 consumer 负载均衡等功能。Consumer在消费partition中的消息的时候,需要将每个partition的offset值记录到zookeeper中。当consumer 重启或者其它 consumer 重新接管该消息分区的消息消费权后,能够从之前的进度开始继续进行消息消费。ZooKeeper 记录 partition 与 consumer 之间的关系,每个 consumer 一旦确定了对一个 partition 的消费权力,需要将其 consumer ID 写入到 ZooKeeper 对应消息分区的临时节点上。

04

使用Kafka

Kafka提供了各种语言版本的SDK,服务端和客户端都很方便接入,当然Java也不例外。SpinrgBoot是目前最流行的Java 框架,其本身也集成了Kafka,利用相应的Jar包非常容易集成Kafka。在SpringBoot中有两种方式集成Kafka,本文以集成消费者来说明。

01

第一种方式

最简单的方式集成,基于 KafkaListener注解来实现。示例代码如下:

基于 KafkaListener注解来实现

通过KafkaListener注解可以让SpringBoot启动kafka客户端消费。Topics指定需要消费的topic,Concurrency配置partition的数量,可以启动相同数量的消费者来消费。

ContainerFactory来指定Kafka配置信息,示例代码如下:

这里需要配置Kafka集群地址、消费者组、每次消费的最大消息数、Offset提交方式等。

02

第二种方式

编程式。示例代码如下:

编程式

原理与第一种方式类似,不同的地方在于手动创建Consumer,然后启动线程死循环消费消息。这种方式比第一种方式更灵活,程序可以灵活的控制消费者线程数量。

05

总结

本文介绍了Kafka的产生背景、六大核心特性,其中高吞吐和低延迟是它最重要的两大特性,也是Kafka得到广泛使用的重要原因。通过分析Kafka组件和架构设计,可以看到高吞吐和低延迟特性主要是由于topic多partition的设计,partition的数量决定了消费的并行消费能力。消息以append log的形式追加到partition中,这是一种顺序写磁盘的机制,效率远高于随机写内存序。通过这些方式,Kafka达到了每秒可以处理10万条消息,在众多的项目中得到了广泛的应用。

- END -

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20210126A01T1900?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券